为什么.setGeometry()不更改QWidget实例的大小?

2022-02-23 00:00:00 python pyqt5

问题描述

我想使用QWidget的.setGeometry(・・・)函数更改QPushButton的大小。我使用以下代码尝试更改按钮的大小。

import sys

from PyQt5           import QtWidgets
from PyQt5.QtCore    import QRect
from PyQt5.QtWidgets import QApplication, QTableWidget, QWidget, QHBoxLayout, QPushButton

class Window(QtWidgets.QMainWindow):
    def __init__(self, method=-1):
        super(Window, self).__init__()

        mainWidget = QWidget()
        mainLayout = QHBoxLayout(mainWidget)

        table = QTableWidget(10, 3)
        button = QPushButton("Why?")

        if   (method == 1):
            print("Method 1:", button.size(), end="")
            button.setMinimumSize(100, 100)
        elif (method == 2):
            print("Method 2:", button.size(), end="")
            button.setGeometry(QRect(0, 0, 100, 100))
        else:
            print("Method X:", button.size(), end="")
        print(" -> ", button.size(), sep="")

        mainLayout.addWidget(table)
        mainLayout.addWidget(button)

        self.setCentralWidget(mainWidget)
        self.show()

if __name__ == "__main__":
    print("python QLayoutGeometry.py[ <MethodToUse=-1>")
    app = QApplication(sys.argv)
    method = -1 if (len(sys.argv) < 2) else int(sys.argv[1])
    GUI = Window(method)
    sys.exit(app.exec_())

但是,当使用setGeometry(···)时,它似乎不会更改2.中按钮的大小。我的理解,因此我的期望,肯定是错误的。谁能澄清一下我写的那部分(不是我所期望的)";

  1. 执行python QLayoutGeometry.py 1调用button.setMinimumSize(100, 100)
    • 确实更改了按钮的大小(与我预期的一致)
    • STDOUT显示:Method 1: PyQt5.QtCore.QSize(640, 480) -> PyQt5.QtCore.QSize(640, 480)(不是我预期的)
  2. 执行python QLayoutGeometry.py 2调用button.setGeometry(QRect(0, 0, 100, 100))
    • 是否未更改按钮的大小(不是我预期的)
    • STDOUT显示:Method 2: PyQt5.QtCore.QSize(640, 480) -> PyQt5.QtCore.QSize(100, 100)(如我所料)
  3. 执行python QLayoutGeometry.py -1不执行任何操作
    • 是否未更改按钮的大小(如我所料)
    • STDOUT显示:Method X: PyQt5.QtCore.QSize(640, 480) -> PyQt5.QtCore.QSize(640, 480)(如我所料)

备注:

  • QPushButton's类层次结构:.QWidget->;QAbstractButton。
  • QWidget's size() function

如果大小超出了由minimumSize()和maxumSize()定义的范围,则调整大小。


解决方案

首先要了解的是,布局管理器顾名思义,管理布局。他们负责定位其中包含的项目并调整其大小,并最终请求设置了这些项目的小工具以扩大其大小。

考虑到这一点,每当设置布局管理器时,调用setGeometry几乎是无用的,特别是在小工具创建阶段完成的情况下,甚至在将小工具添加到布局之前调用它也是没有意义的,这也是出于同样的原因。

然后,您得到的输出是预期的:

  • 默认情况下,尚未展示的新控件初始大小为始终为640x480(如果是父级创建的控件,则初始大小为100x30);
  • 设置最小大小不会改变小工具的当前(默认)大小,除非宽度或高度具有更大的值;
  • 窗口系统最终显示顶层微件并正确调整其大小(如果需要)之前,最终微件的大小不可读,除非顶层微件已明确调整大小和布局已activated()

以下代码将打印正确的大小,即使在__init__内也是如此(但您不应在一般情况下这样做,因为activate是自动调用的):

    mainLayout.addWidget(button)        
    mainLayout.activate()
    print(" -> ", button.size(), sep="")

这就是说:

  • 如果要为小工具设置特定大小,必须使用setFixedSize()
  • 如果需要特定位置或几何图形,则必须结合使用setFixedSize()以及最终的间隔项、布局边距、布局间距和/或应力系数;
  • 布局管理器的存在是为了根据其大小提示(sizeHintminimumSizeHint)、大小约束和大小策略(通常根据系统配置(DPI,默认字体)计算)来优化可用空间,因此,尝试设置固定的几何图形不仅是不受欢迎的,而且可能会适得其反:如果您不考虑这些方面,您可能会有部件变得不可用或与其他部件重叠的风险;

最后,可以调用setGeometry(),但它只能在调整大小事件之后和您完全确定布局已完成其工作之后才能完成,这通常是不可预测的,因为布局的复杂性以及可能存在在多个遍中更新其大小的复杂小部件(如滚动区域);一般规则是,如果您需要使用setGeometrysetGeometry,则即使您需要使用setGeometry,也可以调用setGeometry(),因为布局的复杂性和可能存在的复杂窗口小部件(如滚动区)可能会多次更新其大小;一般情况下,如果您需要使用setGeometry

相关文章