4-5年我需要一个具有以下属性的小部件
应该在布局中使用此子部件,以提供有关布局中其他GUI元素如何工作的一些详细信息,但仅占用最小的空间来显示其内容。
我以为这很容易-但是每次回到挑战时,我总是以放弃而告终。
主要问题是,当实现heightForWidth()并使用带有setHeightForWidth(True)的QSizePolicy时,布局会崩溃。它可以缩小到无限小。显然,这是Qt的错误。
另一种方法是在发生resizeEvent()时调用updateGeometry()并使用与宽度相关的高度来调用setFixedHeight(h)。但是,这也会引起一些奇怪的布局行为。
如果有人对如何解决此问题有任何好的建议,请告诉我。
下面,我包含一个片段,它再现了布局调整大小的行为。
最好的祝福,
狂人
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_())
Run Code Online (Sandbox Code Playgroud)
小智 5
我发现这非常有问题。我认为问题的核心如下:
parentwidget->setLayout(layout))。QLayoutItem派生类(例如QWidgetItem)以稍微复杂的方式完成的。hasHeightForWidth() == true和提供的小部件——int heightForWidth(int width)描述它们对布局的约束的能力有限,因为它们可以提供 a minimumSizeHint()、 asizeHint()和 a heightForWidth(width)。如有必要,它们还可以调用setMinimumSize()和 之类的函数setMaximumSize()。但大多数Qt的布局,比如QVBoxLayout,QHBoxLayout和QGridLayout,不特别注意的heightForWidth(width)提供自己的最小/偏好/最大尺寸,他们的父母时的结果,因为他们通过这样做QLayout::minimumSize(),QLayout::sizeHint()和QLayout::maximumSize()-其中没有一个是所谓的信息关于布局的目标大小(在类似 Catch-22 的情况下),所以他们不能轻易地为width他们的孩子提供价值。setGeometry(const QRect& layout_rect). 现在布局知道它有多大。它为它的孩子分配空间child->setGeometry()。因此,正如您在上面概述的那样,您会看到两类解决方案,其中的大小需要“适当”地限制为所需的大小。
首先:
QLabel采用自动换行衍生的类,或想要以固定它们的纵横比的图像,可以提供他们的最小和最大尺寸,和一个合理的有意义的值sizeHint()(即,他们会大小喜欢来定)。QWidget::resizeEvent(QResizeEvent* event)以找出它们的新宽度(例如 from event->size());(2) 通过自己的heightForWidth()函数计算出他们的首选高度;和 (3) 强制它们的高度,例如,setFixedHeight(height)后跟updateGeometry()。resizeEvent,并且如果父小部件具有 布局hasHeightForWidth() == true,则执行类似setFixedHeight(layout->heightForWidth(width())); updateGeometry();.第二:
parent->setFixedHeight().hasHeightForWidth()并heightForWidth()让新布局(及其父小部件,以及使用此机制的任何祖先布局)调整它们的高度。我已将 C++ 代码放在http://egret.psychol.cam.ac.uk/code/2017_01_16_qt_height_for_width/ 中,用于以下布局:
BoxLayoutHfw, VBoxLayoutHfw, HBoxLayoutHfw-- 替代QBoxLayout等。GridLayoutHfw- 的替代品QGridLayout。FlowLayoutHfw-- 替换 Qt FlowLayout( http://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-example.html )。以及以下小部件:
AspectRatioPixmapLabel -- 图像保持其纵横比;LabelWordWrapWide -- 自动换行标签,尝试在自动换行之前使用尽可能多的水平空间。VerticalScrollArea -- 顾名思义,一个垂直滚动区域,但是一个完全支持高度换宽度的区域。...加上一些基础设施代码(#defines 等),应该使布局恢复到它们的 Qt 等效行为,以及一些支持文件(包括gui_defines.h并layouts.h根据您在这方面的偏好来选择布局和基本小部件)。
我还没有成功解决的一个遗留问题是,我认为在某些情况下,样式表的QLabel'sheightForWidth()似乎返回了稍微错误的值(稍微高估了它的空间要求)。我怀疑问题出在,QLabelPrivate::sizeForWidth但我只是通过计算一些样式表边框来完美地解决它;它仍然不太正确,但高估(导致空白)总比低估(导致剪裁)好。