4 - 5年我需要一个具有以下属性的小部件
应该在布局中使用此子窗口小部件,以提供有关布局中其他GUI元素如何工作但仅占用最小空间以显示其内容的一些详细信息。
我认为这很容易 - 但每当我回到挑战时,我总是放弃。
主要问题是当实现heightForWidth()并且使用带有setHeightForWidth(True)的QSizePolicy时,布局会中断。它可以缩小到无限小。显然这是Qt bug。
另一种方法是在发生resizeEvent()时调用updateGeometry()并使用宽度相关的高度调用setFixedHeight(h)。但这也会产生一些奇怪的布局行为。
如果有人对如何处理这个问题有任何好的建议,请告诉我。
下面我添加了一个重现布局大小调整行为的代码段。
致以最诚挚的问候,
的Mads
import sys
from PyQt4 import QtCore, QtGui
class Square(QtGui.QLabel):
def __init__(self, parent=None):
QtGui.QLabel.__init__(self, parent)
self.setAutoFillBackground(True)
palette = QtGui.QPalette()
palette.setColor(QtGui.QPalette.Window, QtGui.QColor('red'))
self.setPalette(palette)
policy = self.sizePolicy()
policy.setHeightForWidth(True)
self.setSizePolicy(policy)
def sizeHint(self):
return QtCore.QSize(128, 128)
def heightForWidth(self, width):
return width
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
# Call base class constructor
QtGui.QWidget.__init__(self, parent)
# Add a layout
layout = QtGui.QVBoxLayout()
self.setLayout(layout)
# Add Square
label = Square()
layout.addWidget(label)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
layout.addItem(spacerItem)
# Some dummy button
self._push_button = QtGui.QPushButton('Press me')
layout.addWidget(self._push_button)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
widget = Widget()
widget.show()
sys.exit(app.exec_())
答案 0 :(得分:2)
我发现这非常有问题。我认为问题的核心如下:
parentwidget->setLayout(layout)
)。QLayoutItem
派生类(例如QWidgetItem
)以稍微复杂的方式完成的。hasHeightForWidth() == true
并提供int heightForWidth(int width)
的小部件 - 描述其对布局的约束的能力有限,因为它们可以提供{{1} },minimumSizeHint()
和sizeHint()
。如有必要,他们还可以调用heightForWidth(width)
和setMinimumSize()
等函数。但大多数Qt布局,例如setMaximumSize()
,QVBoxLayout
和QHBoxLayout
,在提供自己的最小值/首选/最大值时,请不要特别关注QGridLayout
结果其父级的大小,因为他们通过heightForWidth(width)
,QLayout::minimumSize()
和QLayout::sizeHint()
这样做 - 所有这些都不会被调用有关布局目标大小的信息(在Catch中)这样的情况),所以他们不能轻易地为他们的孩子提供QLayout::maximumSize()
价值。width
调用。现在布局知道它有多大。它通过setGeometry(const QRect& layout_rect)
为其子女分配空间。因此,您可以看到两类解决方案,正如您在上面所概述的那样,大小需要"正确"受限于所需。
第一个:
child->setGeometry()
- 使用自动换行的派生类,或想要修正其宽高比的图像,可以为其最小和最大尺寸提供合理的值,并且是合理的QLabel
(是他们的大小喜欢。)sizeHint()
以找出他们的新宽度(例如来自QWidget::resizeEvent(QResizeEvent* event)
); (2)通过他们自己的event->size()
函数计算他们的首选高度; (3)例如,heightForWidth()
后跟setFixedHeight(height)
。updateGeometry()
,如果父窗口小部件的布局为resizeEvent
,则执行类似hasHeightForWidth() == true
的操作。第二个:
setFixedHeight(layout->heightForWidth(width())); updateGeometry();
重新约束。parent->setFixedHeight()
和hasHeightForWidth()
以使新布局(及其父窗口小部件以及使用此机制的任何祖先布局)进行调整高度。我已将C ++代码放在http://egret.psychol.cam.ac.uk/code/2017_01_16_qt_height_for_width/以获取以下布局:
heightForWidth()
,BoxLayoutHfw
,VBoxLayoutHfw
- HBoxLayoutHfw
的替换等。QBoxLayout
- GridLayoutHfw
的替换。QGridLayout
- 替换Qt' FlowLayoutHfw
(http://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-example.html)。以及以下小部件:
FlowLayout
- 图像保持宽高比; AspectRatioPixmapLabel
- 自动换行标签,在封装之前尝试使用尽可能多的水平空间。LabelWordWrapWide
- 正如其名称所暗示的那样,是一个垂直滚动区域,但是一个可以干净地支持高度宽度的区域。 ...加上一些基础设施代码(VerticalScrollArea
等)应该使布局恢复到他们的Qt等效行为,以及一些支持文件(包括#define
和{{ 1}}使得布局和基本小部件的选择在这方面取决于您的偏好。)
我未能成功解决的一个遗留问题是,我认为gui_defines.h
layouts.h
似乎返回了稍微错误的值(略微过高估计其空间要求)某些情况。我怀疑这个问题出现在QLabel
中,但我通过计算一些样式表边框来解决这个问题并不完美;它仍然不太正确,但过高估计(导致空白)优于低估(导致剪裁)。
答案 1 :(得分:0)
除固定策略外,大小提示不会决定子窗口小部件的大小。如果类似自动调整大小的策略将由父母过剩。