如何为 QAbstractScrollArea 使用 setSizePolicy

How to use setSizePolicy for QAbstractScrollArea

我正在尝试使用 setSizePolicy property of a QWidget. Using this feature with a QWidget or QFrame works as expected. However, using this feature with a QAbstractScrollArea 结果出乎意料。

以下最小工作示例演示了此行为:

排列成两个 Parent 小部件,左边是 QAbstractScrollArea 小部件的布局,右边是一组 QFrame 小部件。每个小部件都分配了一个单独的高度,并且所有小部件在大小策略中指定固定为 sizeHint return 大小,固定为上述高度。

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 小部件一起使用?

当子class小部件时(除了 QWidget 本身),重要的是要记住所有现有的 Qt 子classes 也设置一些默认属性或重新实现方法,包括抽象的。

minimumSizeHint() 推荐的 小部件的最小尺寸,布局将(几乎)始终遵守该尺寸。以下段落很重要:

QLayout will never resize a widget to a size smaller than the minimum size hint unless minimumSize() is set or the size policy is set to QSizePolicy::Ignore. If minimumSize() is set, the minimum size hint will be ignored.

最小提示很重要,因为它仅对布局内的小部件有效,并且它也可以用作 [sub]class“默认”而不是使用 minimumSize(),应该用于实例。

虽然许多小部件 return 无效(如 已忽略 )最小尺寸提示,但其他小部件则没有,因为默认最小尺寸对它们的性质很重要大小设置。 QAbstractButton 的子 class 和 QAbstractScrollArea 的所有子class 都会发生这种情况。

要覆盖此行为(虽然不建议在特定大小下使用),只需覆盖该方法即可。请注意,最好使用 sizeHint() return minimumSizeHint() 而不是相反,这样 sizeHint() 始终遵守最小提示,但仍可以在其他子中被覆盖classes.

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):
        <b>return self.minimumSizeHint()

    def minimumSizeHint(self):
        return QtCore.QSize(100, self._height)</b>