如何为 QAbstractScrollArea 使用 setSizePolicy
Posted
技术标签:
【中文标题】如何为 QAbstractScrollArea 使用 setSizePolicy【英文标题】:How to use setSizePolicy for QAbstractScrollArea 【发布时间】:2021-01-13 23:45:53 【问题描述】:我正在尝试使用 QWidget 的 setSizePolicy 属性。将此功能与QWidget 或QFrame 一起使用可以按预期工作。但是,将此功能与 QAbstractScrollArea 一起使用会产生意想不到的结果。
以下最小工作示例演示了这种行为:
布置在两个Parent
小部件中,左侧是QAbstractScrollArea 小部件的布局,右侧是一组QFrame 小部件。每个小部件都被分配一个单独的高度,并且所有小部件都在尺寸策略中指定要固定为 sizeHint 返回尺寸,该尺寸固定为上述高度。
from PyQt5 import QtCore, QtWidgets
import sys
class ASWidget(QtWidgets.QAbstractScrollArea):
def __init__(self, height, parent=None):
super().__init__(parent)
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self._height = height
self.setStyleSheet("background: red;")
def sizeHint(self):
return QtCore.QSize(100, self._height)
class NonASWidget(QtWidgets.QFrame):
def __init__(self, height, parent=None):
super().__init__(parent)
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self._height = height
self.setStyleSheet("background: red;")
def sizeHint(self):
return QtCore.QSize(100, self._height)
class ParentWidget(QtWidgets.QWidget):
def __init__(self, classType, parent=None):
super().__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(1)
sizes = [5, 15, 25, 35, 45, 55, 65]
for i in sizes:
layout.addWidget(classType(i))
class Dialog(QtWidgets.QDialog):
def __init__(self):
super().__init__()
w1 = ParentWidget(ASWidget, self)
w2 = ParentWidget(NonASWidget, self)
w2.move(110, 0)
def main():
app = QtWidgets.QApplication(sys.argv)
dialog = Dialog()
dialog.show()
app.exec_()
if __name__ == "__main__":
main()
上面代码的结果是这个屏幕截图:
如您所见,与右侧的 QFrame 小部件相比,左侧的 QAbstractScrollArea 小部件不使用固定大小策略。
这背后的原因是什么?如何将 setSizePolicy 功能与 QAbstractScrollArea 小部件一起使用?
【问题讨论】:
您的问题有什么意义?另外,您是否考虑过最小尺寸提示? @musicamante 我想重载从 QAbstractScrollArea 继承的小部件的 sizeHint 并用它显式设置小部件的大小。使用 setFixedHeight 效果很好,但我认为另一种方法更清洁(如果可以的话)。 我明白你想做什么,我说的不是尺寸提示,也不是固定尺寸,而是minimumSizeHint()
【参考方案1】:
当子类化小部件时(除了 QWidget 本身),重要的是要记住所有现有的 Qt 子类还设置了一些默认属性或重新实现方法,包括抽象的。
minimumSizeHint()
是 推荐 小部件的最小尺寸,布局将(几乎)始终尊重这一点。以下段落很重要:
除非设置了 minimumSize() 或将大小策略设置为 QSizePolicy::Ignore,否则 QLayout 永远不会将小部件的大小调整为小于最小大小提示的大小。如果设置了 minimumSize(),则忽略最小尺寸提示。
最小提示很重要,因为它仅对布局内的小部件有效,并且它也可以用作 [子] 类“默认”而不是使用 minimumSize()
,而应该将其用于实例。
虽然许多小部件返回无效(如 忽略 中的)最小尺寸提示,但其他小部件不会,因为设置默认最小尺寸对它们的性质很重要。这发生在 QAbstractButton 的子类和 QAbstractScrollArea 的所有子类中。
要覆盖此行为(虽然不建议在特定大小下),只需覆盖该方法即可。请注意,最好让sizeHint()
返回minimumSizeHint()
,而不是相反,这样sizeHint()
始终遵循最小提示,但仍然可以在其他子类中被覆盖。
class ASWidget(QtWidgets.QAbstractScrollArea):
def __init__(self, height, parent=None):
super().__init__(parent)
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self._height = height
self.setStyleSheet("background: red;")
def sizeHint(self):
return self.minimumSizeHint()
def minimumSizeHint(self):
return QtCore.QSize(100, self._height)
【讨论】:
非常感谢您的详细回答。这绝对解决了我的问题。但是,重载 minimumSizeHint 方法以返回无效的最小大小并将 sizeHint 用于其预期目的不是更“正确”吗?如果这个建议有任何意义,您能否也说明一下这种方法? @Woltan 这取决于您打算对小部件做什么,它的目的是什么以及它应该显示什么内容。考虑到你只是一个例子,我不知道你打算做什么(例如,你添加了没有主布局的父小部件,通常不应该这样做),但如果你这样做,结果就是如果没有有效的最小提示,小部件可能会变得太小。对于滚动区域,这不是一个好主意,因为内容将变得几乎不可见并且滚动条无法使用。对于像这样的复杂小部件,您应该始终提供 有效 最小提示。 @musicamente 你是对的,我的示例没有显示我打算使用小部件的目的。在我的情况下,小部件没有任何滚动条,而是“从外部”滚动,并且小尺寸足以做到这一点。根据您的评论,我得出结论,可以超载 minimumSizeHint ,这就是我在接受您的回答后要做的事情。再次感谢您的帮助!以上是关于如何为 QAbstractScrollArea 使用 setSizePolicy的主要内容,如果未能解决你的问题,请参考以下文章
Sublime Monokai 语法突出显示:如何为方法调用着色并使插值字符串内部的颜色不同
CSS/JQuery:如何为表格行创建子菜单,使鼠标从行到菜单保持可见?
如何防止 QAbstractScrollArea / QTableView 水平滚动?