PyQt:使用布局管理器强制执行两个小部件应有的sizeHint()尺寸

4
我有两个小部件,一个是WidgetA,另一个是WidgetB,它们相邻放置在一个QDialog上,并使用水平布局管理器。
我正在尝试实施以下大小/调整策略:
对于WidgetA
  • 水平方向:宽度应为900,具有收缩能力(最多100),以及扩展能力(到任何值)。
  • 垂直方向:高度应为600,具有扩展能力(到任何值)。
对于WidgetB
  • 水平方向:宽度应固定为600。
  • 垂直方向:高度应为600,具有扩展能力(到任何值),与WidgetA相同。
但无论我为WidgetA选择哪种大小策略,它仍然无法占据宽度为900的空间。
以下是代码示例:
class WidgetA(QTextEdit):

    def __init__(self, parent = None):
        super(WidgetA, self).__init__(parent)
        #self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)   --> WidgetA width still smaller than 900
        #self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.MinimumExpanding)     --> WidgetA will be set to minimumSizeHint()
        #self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)       --> not good for me, since I want WidgetA to be able to shrink up to minimumSizeHint().width()
        #self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding)     --> not good for me for the same reason - I want WidgetA to be able to shrink up to minimumSizeHint().width()

    def minimumSizeHint(self):
        return QSize(100, 600)

    def sizeHint(self):
        return QSize(900, 600) 


class WidgetB(QTextEdit):

    def __init__(self, parent = None):
        super(WidgetB, self).__init__(parent)
        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)

    def sizeHint(self):
        return QSize(600, 600)

class MainForm(QDialog):

    def __init__(self, parent = None):
        super(MainForm, self).__init__(parent)

        label_a = QLabel('A')
        widget_a = WidgetA()
        label_a.setBuddy(widget_a)

        label_b = QLabel('B')
        widget_b = WidgetB()
        label_b.setBuddy(widget_b)

        hbox = QHBoxLayout()

        vbox = QVBoxLayout()
        vbox.addWidget(label_a)
        vbox.addWidget(widget_a)
        widget = QWidget()
        widget.setLayout(vbox)

        hbox.addWidget(widget)

        vbox = QVBoxLayout()
        vbox.addWidget(label_b)
        vbox.addWidget(widget_b)
        widget = QWidget()
        widget.setLayout(vbox)

        hbox.addWidget(widget)

        self.setLayout(hbox)



def run_app():
    app = QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    run_app()

最接近的设置是当我设定:
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)

WidgetA 上。

enter image description here

看起来像是WidgetB 占用了 WidgetA 的900宽度(移除 WidgetB 就可以解决),但我不应该受制于窗口的宽度。
是什么阻止了窗口本身MainForm)自动水平扩展以便同时考虑 WidgetA 的900宽度和 WidgetB 的固定600宽度?

1个回答

6
根据 布局管理 文章介绍,添加小部件时应遵循以下规则:
  1. 所有小部件最初将根据其 QWidget::sizePolicy() 和 QWidget::sizeHint() 分配一定量的空间。
  2. 如果任何小部件设置了大于零的拉伸因子,则它们按比例分配空间(下面会进行解释)。
  3. 如果任何小部件的拉伸因子设置为零,则只有在没有其他小部件需要空间时才会分配更多空间。其中,先为具有“可扩展”大小策略的小部件分配空间。
  4. 任何分配的空间少于其最小大小(或最小大小提示,如果未指定最小大小)的小部件都被分配所需的最小大小。(小部件不必具有最小大小或最小大小提示,此时拉伸因子是它们的决定因素。)
  5. 任何被分配的空间超过其最大大小的小部件都会被分配所需的最大大小。(小部件不必具有最大大小,此时拉伸因子是它们的决定因素。)
因此,您可以定义 sizeHintminimumSizeHint,设置比其他小部件大的拉伸因子,并将大小策略设置为 Expanding。但即使有了这些措施,似乎布局管理器仍然无法保证在最小大小提示较小时会遵守大小提示。
问题在于 Expanding 的定义不够强:

sizeHint() 是一个合理的大小,但小部件可以缩小并仍然是有用的。小部件可以利用额外的空间,因此应尽可能获得更多的空间(例如,水平滑块的水平方向)。

由于某种原因,如果另一个小部件具有更强的大小策略(例如 Fixed),布局管理器似乎优先考虑缩小而不是扩展。从您的例子的角度来看,这似乎是错误的选择,但我想可能还有其他情况更合理。该行为在 Qt4 和 Qt5 中完全相同,因此我不知道是否应将其视为错误或实现的怪癖。
我能想到的最简单的解决方法是像这样强制执行 widget_a 的大小提示:
class MainForm(QDialog):

    def __init__(self, parent = None):
        ...

        self.setLayout(hbox)

        widget_a.setMinimumSize(widget_a.sizeHint())
        self.adjustSize()
        widget_a.setMinimumSize(widget_a.minimumSizeHint())

(注:仅在使用Openbox窗口管理器的Linux系统上进行了测试。)
PS:还可以参考这个相似的SO问题:调整窗口大小以适应内容

1
完美,谢谢。 我也感觉“Expanding”的定义不够强。 我认为建议的解决方法会很好。 - so.very.tired

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接