【问题标题】:PyQt5: How to Get Dimensions of Displayed WidgetsPyQt5:如何获取显示的小部件的尺寸
【发布时间】:2022-01-19 02:05:26
【问题描述】:

我有 PyQt5 QLabels,它们会随着 QMainWindow 大小的变化而扩展/收缩。当 QMainWindow 的大小调整到其初始尺寸以外的任何尺寸时,我想获取 QLabels 的尺寸。

下面的脚本在 QMainWindow 中创建了两个 QLabel。 QLabel 扩展,但顶部 QLabel 具有固定高度。 QMainWindow 的创建尺寸为 400x300,并显示为使用 showMaximized() 最大化的屏幕(在我的情况下为 1920 x 1080)。该脚本在 QMainWindow 显示之前和之后打印 QLabels 的尺寸。在显示之前,width()height() 返回默认 QLabel 值,在显示(屏幕最大化)之后width()height() 返回值,就好像 QMainWindow 的物理尺寸为 400x300。这是 wat 打印出来的:

label_1 Size Before Expanding:  100 100
label_2 Size Before Expanding:  100 30
label_1 Size After Expanding:  378 100
label_2 Size After Expanding:  378 171

当 QMainWindow 最大化时,如何获得 QLabels 的真实尺寸?我在 Windows 环境中运行。

from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QLabel, QVBoxLayout, QWidget
import sys

class MainWindow(QMainWindow):  
    def __init__(self, parent=None):
        super().__init__(parent)
        
        central_widget = QWidget()
        self.setCentralWidget(central_widget)        
        self.setGeometry(100, 100, 400, 300)
        self.layout = QVBoxLayout(central_widget)
        
        self.label_1 = QLabel(self)
        self.label_1.setStyleSheet('background-color: green')
        self.label_1.setFixedHeight(100)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.label_1.setSizePolicy(sizePolicy)
        self.layout.addWidget(self.label_1)
        
        self.label_2 = QLabel(self)
        self.label_2.setStyleSheet('background-color: red')
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.label_2.setSizePolicy(sizePolicy)
        self.layout.addWidget(self.label_2)
        
        print('label_1 Size Before Expanding: ', self.label_1.width(), self.label_1.height())
        print('label_2 Size Before Expanding: ', self.label_2.width(), self.label_2.height())
        self.showMaximized()
        print('label_1 Size After Expanding: ', self.label_1.width(), self.label_1.height())
        print('label_2 Size After Expanding: ', self.label_2.width(), self.label_2.height())
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    app.exec()

【问题讨论】:

  • 只是出于好奇,您为什么需要知道这些?
  • 我有两个垂直裁剪的视频窗口。我认为在隐藏另一个窗口及其水平和垂直滑块时强制它们到全屏尺寸将使它们无法调整大小。感谢您引导我进行 resizeEvent - 我认为这会起作用。
  • 抱歉,我不明白:“两个垂直裁剪的视频窗口”是什么意思?为什么最大化应该防止在隐藏小部件时调整剩余小部件的大小?我开始认为你问这个问题的原因是错误的。
  • 我有两个垂直堆叠的视频窗口,每个都有一个水平滑块(仅在回放期间)。我有两个实时视频流进来。对于每个流,我裁剪到中间的 50%,将其写入记录器并显示它。在重播模式下,未重播的窗口消失(隐藏()),但重播视频的窗口改变了尺寸,这是我不想要的。我尝试了不同的大小策略、屏蔽等。主窗口将始终最大化。我认为如果我在最大化后将 QLabel 大小策略更改为 Fixed,那么它们将不会更改维度。这应该是一个简单的解决方案
  • 我不确定我是否理解您的要求:如果视频小部件被隐藏,预期的结果是什么?主窗口是否应该保持其最大化大小,并且只是隐藏视频小部件,在窗口上留下“空白”空间?或者您想相应地调整主窗口的大小(因此,使其垂直变小)?在第一种情况下,使用setRetainSizeWhenHidden()。第二个稍微复杂一点:最大化的窗口不能调整大小,你必须再次使其正常并手动更新其几何形状。

标签: pyqt5 pyside2 qwidget dimensions qlabel


【解决方案1】:

当小部件已创建但尚未在屏幕上映射(“显示”)时,它们始终具有默认大小:

  • 100x30 适用于所有 明确 设置了父级的小部件(通过在构造函数中添加父级参数,或通过调用 setParent());
  • 640x480 适用于所有顶级小部件(未明确设置父级的小部件);

唯一的例外是存在尺寸限制时,例如您的情况:第一个标签具有固定高度,这就是输出中显示的内容(请记住,“固定尺寸”意味着 两者最小和最大尺寸相同)。

第一次调用 show()setVisible(True) 时,会在顶层或父窗口小部件上自动创建(以及其他)Resize 事件,该事件会自动激活该窗口小部件的布局并最终递归创建 Resize 事件对于由其布局管理的所有小部件,基于布局计算。这不会在第一次显示小部件之前发生。

这样做是出于优化的原因:更新布局可能要求很高,尤其是对于具有多个嵌套布局的复杂 UI,其中包含具有不同大小提示、策略、拉伸等的小部件。

由于几何图形会在窗口显示后立即更新,因此在完整布局完成之前设置大小是没有意义的。另请注意,使用setGeometry()resize() prior 第一次显示小部件将不会激活布局,如上所述。

也就是说,即使小部件尚未显示,也可以根据当前布局更新尺寸:您必须明确activate() 布局管理器。

但是,请注意:为了根据布局获得正确的尺寸,您需要激活 所有 布局,直到顶层小部件。 QMainWindow 有自己的私有布局,所以你也需要激活它。
由于您已经用self.layout 覆盖了默认的layout() 函数,因此访问它的唯一方法是通过super() 调用。

然后,还有另一个问题:改变窗口状态(最大化、最小化、全屏和正常)的函数直接调整窗口大小。这些函数(包括setWindowState())实际上“要求”操作系统更改窗口状态,然后操作系统将自行决定请求是否可接受,并最终根据请求状态根据其行为调整窗口大小。
调整大小将在调用之后的 undefined 点发生,并且没有直接的方法可以知道何时:操作系统可能有一些花哨的动画来显示状态变化,这可能会导致大小的连续变化甚至在该“过程”完成后突然更改为新大小。即使使用processEvents() 也是不够的,因为该函数只处理由Qt 直接处理的事件,而Qt 对外部操作系统事件一无所知。

在任何调整大小后确定小部件大小的唯一方法是覆盖resizeEvent()

class MainWindow(QMainWindow):  
    def __init__(self, parent=None):
        # ...
        super().layout().activate()
        self.layout.activate()
        
        print('label_1 Size Before Showing: ', self.label_1.size())
        print('label_2 Size Before Showing: ', self.label_2.size())
        self.showMaximized()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        print('label_1 Size After Showing/Resizing: ', self.label_1.size())
        print('label_2 Size After Showing/Resizing: ', self.label_2.size())

这将在showMaximized()之前正确打印:

label_1 Size Before Expanding:  PyQt5.QtCore.QSize(388, 100)
label_2 Size Before Expanding:  PyQt5.QtCore.QSize(388, 182)
label_1 Size After Resizing:  PyQt5.QtCore.QSize(388, 100)
label_2 Size After Resizing:  PyQt5.QtCore.QSize(388, 182)
label_1 Size After Resizing:  PyQt5.QtCore.QSize(1428, 100)
label_2 Size After Resizing:  PyQt5.QtCore.QSize(1428, 757)

注意resizeEvent 被调用了两次:第一次是在任何show*() 调用之后,第二次是当窗口实际最大化时。如果您删除上面的 activate 调用,第一个输出将与开头解释的默认值相同。

【讨论】:

  • 哇 - 另一个精彩的解释。这很有意义。
【解决方案2】:

要获得真实大小,我认为您需要触发 resizeEvent。我不知道在查询大小之前强制事件循环完成最大化的方法。当您在 __init__ 中运行它时,即使 app.processEvents() 似乎对此也没有影响:

from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QLabel, QVBoxLayout, QWidget
import sys

class MainWindow(QMainWindow):  
    def __init__(self, parent=None):
        super().__init__(parent)
        
        central_widget = QWidget()
        self.setCentralWidget(central_widget)        
        self.setGeometry(100, 100, 400, 300)
        self.layout = QVBoxLayout(central_widget)
        
        self.label_1 = QLabel(self)
        self.label_1.setStyleSheet('background-color: green')
        self.label_1.setFixedHeight(100)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.label_1.setSizePolicy(sizePolicy)
        self.layout.addWidget(self.label_1)
        
        self.label_2 = QLabel(self)
        self.label_2.setStyleSheet('background-color: red')
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.label_2.setSizePolicy(sizePolicy)
        self.layout.addWidget(self.label_2)
        self.show()
        # ~ print('label_1 Size Before Expanding: ', self.label_1.width(), self.label_1.height())
        # ~ print('label_2 Size Before Expanding: ', self.label_2.width(), self.label_2.height())
        self.showMaximized()
        # ~ print('label_1 Size After Expanding: ', self.label_1.width(), self.label_1.height())
        # ~ print('label_2 Size After Expanding: ', self.label_2.width(), self.label_2.height())
        
    def resizeEvent(self, event):
        print('label_1 Size : ', self.label_1.width(), self.label_1.height())
        print('label_2 Size : ', self.label_2.width(), self.label_2.height())
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    app.exec()

给了

label_1 Size :  100 100
label_2 Size :  100 30
label_1 Size :  1268 100
label_2 Size :  1268 869

【讨论】:

  • 太棒了!完美运行!
猜你喜欢
  • 2020-04-24
  • 2019-06-01
  • 1970-01-01
  • 2020-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
相关资源
最近更新 更多