PyQt5:如何获取显示小部件的尺寸

问题描述 投票:0回答:2

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

下面的脚本在 QMainWindow 中创建两个 QLabel。 QLabel 展开,但顶部 QLabel 具有固定高度。 QMainWindow 的创建尺寸为 400x300,并使用

showMaximized()
显示为最大化的屏幕(在我的例子中,为 1920 x 1080)。该脚本在 QMainWindow 显示之前和之后打印 QLabels 的尺寸。在显示之前,
width()
height()
返回默认的 QLabel 值,在显示之后(屏幕最大化)
width()
height()
返回值,就好像 QMainWindow 的物理尺寸为 400x300 一样。这是打印的:

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()
pyqt5 pyside2 qwidget dimensions qlabel
2个回答
5
投票

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

  • 100x30 对于所有具有父显式设置的小部件(通过在构造函数中添加父参数,或通过调用
    setParent()
    );
  • 640x480 对于所有顶级小部件(没有父显式设置的小部件);

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

第一次调用

show()

setVisible(True)
 时,会在顶层或父窗口小部件上自动创建(除其他外)一个 
Resize
 事件,该事件会自动激活该窗口小部件的布局,并最终递归地为所有窗口创建 
Resize
 事件基于布局计算,由其布局管理的小部件。在第一次显示小部件之前,这不会发生。
这样做是出于优化原因:更新布局可能非常困难,特别是对于具有多个嵌套布局的复杂 UI,其中包含具有不同大小提示、策略、拉伸等的小部件。

由于一旦显示窗口,几何图形就会更新,因此在完整布局完成之前设置尺寸是没有意义的。另请注意,第一次使用

setGeometry()

resize()

 
prior
 显示小部件将
不会 激活布局,如上所述。 也就是说,即使尚未显示小部件,也可以根据当前布局更新尺寸:您必须显式地

activate()

布局管理器。这通常也可以通过调用布局的 sizeHint()

after
在其小部件上设置来实现。
但是,请注意:为了根据布局获得正确的尺寸,您需要激活
所有布局,直到顶级小部件。 QMainWindow 有自己的私有布局,因此您也需要激活它。 由于您已使用

layout()

覆盖了默认的 self.layout
函数,因此访问它的唯一方法是通过

super()
调用。
然后,还有另一个问题:更改窗口状态(最大化、最小化、全屏和正常)的函数不会直接调整窗口大小。这些函数(包括
setWindowState()
)实际上“请求”操作系统更改窗口状态,然后操作系统将自行决定请求是否可接受,并最终根据请求状态根据其行为调整窗口大小。
调整大小将在调用后的“未定义”点发生,并且没有直接的方法知道何时:操作系统可能有一些奇特的动画来显示状态更改,这可能会导致大小连续变化,甚至突然变化“过程”完成后调整为新尺寸。即使使用

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
调用,第一个输出将与开头解释的默认值相同。


要获得真实大小,我认为您需要触发 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()
这给出了


3
投票


© www.soinside.com 2019 - 2024. All rights reserved.