so.*_*red 4 python layout pyqt qsizepolicy
我有两个小部件,彼此相邻,WidgetA并且WidgetB在一个上QDialog,带有水平布局管理器。
我正在尝试强制执行以下大小/调整大小策略:
对于WidgetA:
为了WidgetB:
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()
Run Code Online (Sandbox Code Playgroud)
我能得到的最接近的是当我设置时:
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
Run Code Online (Sandbox Code Playgroud)
在WidgetA。
看起来好像WidgetB是要咬掉WidgetA900 的宽度(消除WidgetB就可以了),但我不应该受到窗口宽度的限制。
是什么阻止窗口本身(MainForm)自动水平扩展以同时考虑 的WidgetA900 宽度和WidgetB固定 600 宽度?
根据布局管理上的文章,添加小部件时应用的规则如下:
- 所有小部件最初都会根据它们的 QWidget::sizePolicy() 和 QWidget::sizeHint() 分配一定量的空间。
- 如果任何小部件设置了拉伸因子,且拉伸因子的值大于零,则它们将按照拉伸因子的比例分配空间(如下所述)。
- 如果任何小部件的拉伸因子设置为零,则只有在没有其他小部件需要空间时,它们才会获得更多空间。其中,空间首先分配给具有扩展大小策略的小部件。
- 任何分配的空间小于其最小大小(如果未指定最小大小则为最小大小提示)的小部件都会分配它们所需的最小大小。(小部件不必具有最小尺寸或最小尺寸提示,在这种情况下,拉伸因子是它们的决定因素。)
- 任何分配的空间超过其最大大小的小部件都会分配它们所需的最大大小空间。(小部件不必具有最大尺寸,在这种情况下,拉伸因子是它们的决定因素。)
因此,您最多可以定义sizeHint和minimumSizeHint,设置一个大于所有其他的拉伸因子,并设置大小策略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())
Run Code Online (Sandbox Code Playgroud)
(注意:仅在使用 Openbox 窗口管理器的 Linux 上进行了测试)。
PS:另请参阅这个非常相似的问题:Resize window to fit content。