Pyqt:使用布局管理器在双小部件应用程序上强制执行 sizeHint() 尺寸

Pyqt: Enforcing sizeHint() dimensions on two-widget app with layout manager

我有两个并排放置的小部件,WidgetAWidgetB,在 QDialog 上,带有水平布局管理器。
我正在尝试执行以下 size/resize 政策:
对于 WidgetA

对于WidgetB:

但是无论我为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

似乎 WidgetB 正在蚕食 WidgetA 的 900 宽度(消除 WidgetB 就可以了),但我不应该受限于 window的宽度。
是什么阻止 window 本身 MainForm)自动水平扩展以考虑 WidgetA 的 900 宽度和 WidgetB的固定宽度600?

根据Layout Management上的文章,添加小部件时应用的规则如下:

  1. All the widgets will initially be allocated an amount of space in accordance with their QWidget::sizePolicy() and QWidget::sizeHint().
  2. If any of the widgets have stretch factors set, with a value greater than zero, then they are allocated space in proportion to their stretch factor (explained below).
  3. If any of the widgets have stretch factors set to zero they will only get more space if no other widgets want the space. Of these, space is allocated to widgets with an Expanding size policy first.
  4. Any widgets that are allocated less space than their minimum size (or minimum size hint if no minimum size is specified) are allocated this minimum size they require. (Widgets don't have to have a minimum size or minimum size hint in which case the stretch factor is their determining factor.)
  5. Any widgets that are allocated more space than their maximum size are allocated the maximum size space they require. (Widgets do not have to have a maximum size in which case the stretch factor is their determining factor.)

所以您最多只能定义 sizeHintminimumSizeHint,设置一个比所有其他的都大的拉伸因子,并设置 Expanding 的大小策略。但是即使有了所有这些东西,布局管理器似乎仍然仍然不能保证在最小尺寸提示较小时遵守尺寸提示。

问题是Expanding的定义不够相当:

The sizeHint() is a sensible size, but the widget can be shrunk and still be useful. The widget can make use of extra space, so it should get as much space as possible (e.g. the horizontal direction of a horizontal slider).

无论出于何种原因,如果另一个小部件具有更强的尺寸策略(例如 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())

(注意:仅在 Linux 上使用 Openbox window 管理器进行了测试。

PS:另请参阅这个非常相似的 SO 问题:Resize window to fit content.