为什么没有显示绝对定位的小部件?

Why is an absolute positioned widget not shown?

我正在使用 Qt5 尝试使用绝对定位使小部件工作。下面的代码是我正在尝试做的事情的最小工作示例。快速浏览代码:

我注释掉了两行代码。通过向 CentralWidget 添加布局,第一个 "enables" 使用布局的相对定位。这条线显示了我想要实现的目标,但具有绝对定位。第二个注释启用一些调试信息:

MyWidget
  layout.count: 3
  size: PyQt5.QtCore.QSize(-1, -1)
  sizeHint: PyQt5.QtCore.QSize(200, 100)

CentralWidget
  size: PyQt5.QtCore.QSize(18, 18)
  sizeHint: PyQt5.QtCore.QSize(18, 18)

为了让 MyWidget 使用绝对定位可见,我做错了什么?

代码:

from PyQt5 import QtCore, QtWidgets
import sys


class MyWidget(QtWidgets.QWidget):
    z = 0

    def __init__(self, parent):
        super().__init__(parent)

        self._layout = QtWidgets.QVBoxLayout(self)

    def SetData(self):
        while self._layout.count() > 0:
            widget = self._layout.takeAt(0).widget()
            widget.hide()
            widget.deleteLater()

        for i in range(3):
            self._layout.addWidget(QtWidgets.QLabel(str(MyWidget.z * 10 + i)))

        MyWidget.z += 1


class CentralWidget(QtWidgets.QWidget):
    def __init__(self, parent):
        super().__init__(parent)

        self._myWidget = MyWidget(self)

        # QtWidgets.QHBoxLayout(self).addWidget(self._myWidget)

    def SetData(self):
        self._myWidget.SetData()
        # print("MyWidget\n  layout.count: {}\n  size: {}\n  sizeHint: {}\n\nCentralWidget\n  size: {}\n  sizeHint: {}\n\n".format(self._myWidget.layout().count(), self.sizeHint(), self.size(), self._myWidget.sizeHint(), self._myWidget.size()))


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        centralWidget = CentralWidget(self)
        self.setCentralWidget(centralWidget)

        self._timer = QtCore.QTimer(self)
        self._timer.timeout.connect(centralWidget.SetData)
        self._timer.start(500)


def main():
    app = QtWidgets.QApplication(sys.argv)

    mainWindow = MainWindow()
    mainWindow.show()

    app.exec_()


if __name__ == "__main__":
    main()

此行为的原因与小部件未添加到布局这一事实直接相关并且其内容是在显示后添加的。

事实上,如果您在初始化时和 mainWindow.show() 之前调用 centralWidget.SetData(),它将按预期工作。

当您将子部件添加到布局时会发生很多事情,这通常涉及对子部件尺寸提示的多次调用,允许父部件调整自己的尺寸提示,并且,之后that,调整其大小及其子项的大小。

如果 "container widget" 本身包含在另一个布局中,则该小部件将在下一个事件周期中自动调整大小(基于其提示),但这不会发生在你的情况下,因为你的是一个 "free" 小部件。

您要查找的函数是QWidget.adjustSize(),但是,由于上述原因,您无法在添加子控件后立即调用它。
要解决您的问题,您可以在 adjustSize() 之前调用 QApplication.processEvents(),或者最终使用基于 0 的单发 QTimer:

    def SetData(self):
        while self._layout.count() > 0:
            widget = self._layout.takeAt(0).widget()
            widget.hide()
            widget.deleteLater()

        for i in range(3):
            self._layout.addWidget(QtWidgets.QLabel(str(MyWidget.z * 10 + i)))

        MyWidget.z += 1

        QtCore.QTimer.singleShot(0, self.adjustSize)