如何为 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 水平滚动?

如何为Android创建小于O的通知通道

如何为 UITableViews 裁剪 cell.imageview.image 中的图像?

如何为图像添加渐变?