代码之家  ›  专栏  ›  技术社区  ›  so.very.tired

Pyqt:使用布局管理器在两个小部件应用程序上强制执行sizeHint()维度

  •  4
  • so.very.tired  · 技术社区  · 7 年前

    我有两个小部件,一个挨着一个, WidgetA WidgetB QDialog ,具有水平布局管理器。
    我正在尝试实施以下大小/大小调整策略:
    威吉塔 :

    对于 WidgetB公司 :

    • 垂直方向:高度应为600,具有扩展(到任何位置)的能力-与 威吉塔

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

    在…上 威吉塔

    enter image description here

    看起来像是 WidgetB公司 's 900宽(消除 WidgetB公司 但是我不应该受到窗户宽度的限制。
    是什么阻止了 MainForm )自动水平扩展以同时考虑两者 威吉塔 WidgetB公司 的固定宽度为600?

    1 回复  |  直到 7 年前
        1
  •  6
  •   ekhumoro    7 年前

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

    1. 所有小部件最初将根据其QWidget::sizePolicy()和QWidget::sizeHint()分配一定量的空间。
    2. 其拉伸系数(解释如下)。
    3. 空间首先分配给具有扩展大小策略的小部件。
    4. 分配的任何小部件的空间小于其最小大小(如果未指定最小大小,则为最小大小提示) 尺寸或最小尺寸提示,在这种情况下,拉伸系数是其 决定因素。)
    5. 必须具有最大尺寸,在这种情况下,拉伸系数为

    所以你能做的就是定义 sizeHint minimumSizeHint Expanding . 但即使有了所有这些东西,布局管理器似乎是 当最小尺寸提示较小时,不保证遵守尺寸提示。

    问题是 Expanding 不是 足够强壮:

    sizeHint()是一个合理的大小,但小部件可以缩小并 获得尽可能多的空间(例如 水平滑块)。

    Fixed ). 从你的例子来看,这似乎是一个错误的选择,但我认为可能还有其他更合理的情况。Qt4和Qt5中的行为似乎完全相同,所以我不知道这是一个bug,还是只是实现的一个怪癖。

    为了修复您的示例,我能想到的最简单的解决方法是强制执行 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问题: Resize window to fit content