PyQt6 对嵌套布局或小部件感到困惑

PyQt6 confused about nesting layouts or widgets

我试图了解布局和小部件的嵌套是如何工作的,所以我取出了所有初始化参数并改用 .setWhatever、.setParent、.setText 等。除了 QtWidgets.QVBoxLayout 小部件的第二个和第三个外,这都有效;对于第一个,它将其父项设置为 frame_main,对于第二个和第三个,它将其设置为 frame_sensor。这两个 frame_ 小部件都是 QtWidgets.QFrame 类型。当第二个和第三个 QVBoxLayout 小部件使用 setParent (frame_sensor) 时,它会生成消息“布局只能将另一个布局作为父布局”,但是如果我使用 QtWidgets.QVBoxLayout (frame_sensor) 没有抱怨。有人可以解释为什么有时我可以使用 .setParent 有时不能使用或者出了什么问题吗?

import sys
import time

from PyQt6 import QtGui
from PyQt6 import QtWidgets
from PyQt6 import QtCore

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

        self.widgets = { }

        self.frame_main = QtWidgets.QFrame()

        self.frame_main.setParent(self)
        self.frame_main.setObjectName("frame_main")

        self.layout_top = QtWidgets.QVBoxLayout()

        self.layout_top.setParent(self.frame_main)
        self.layout_top.setObjectName("layout_top")

        self.frame_main.setLayout(self.layout_top)

        self.setCentralWidget(self.frame_main)

        self.show()

        self.add_sensor("sensor1", 123)
        self.add_sensor("sensor2", 234)

    def add_sensor(self, sensor, value):
        label_title = QtWidgets.QLabel()

        label_title.setText(sensor)
        label_title.setObjectName("label_title")

        label_value = QtWidgets.QLabel()

        label_value.setText("{:.1f}".format(float(value)))
        label_value.setObjectName("label_value")

        frame_sensor = QtWidgets.QFrame()

        frame_sensor.setObjectName("frame_sensor")
        frame_sensor.setStyleSheet("border: 2px solid;")

        # also makes frame_sensor the child of frame_main
        self.layout_top.addWidget(frame_sensor)

        # this works
        #layout_vbox = QtWidgets.QVBoxLayout(frame_sensor)

        # this doesn't work
        layout_vbox = QtWidgets.QVBoxLayout()
        layout_vbox.setParent(frame_sensor)

        layout_vbox.setObjectName("layout_vbox")
    
        layout_vbox.addWidget(label_title)
        layout_vbox.addWidget(label_value)

        self.widgets.update({ sensor : label_value })

    def closeEvent(self, event):
        event.accept()
        sys.exit()

if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    window = MainWindow()

    app.exec()

没有文档表明 setParent() 的 objective 之一是建立一个小部件,布局将处理其 children 的几何形状。如果你想这样做,有 2 个选项:

  • 在布局构造函数中指明。
layout_vbox = QtWidgets.QVBoxLayout(frame_sensor)
  • 或者使用QWidget的setLayout方法。
layout_vbox = QtWidgets.QVBoxLayout()
frame_sensor.setLayout(layout_vbox)

setParent()的objective是在QObjects之间建立层次结构,以便能够处理children的内存(所有权),因为Qt实现了[的创建=37=] 在堆中。所以逻辑是,如果父亲从内存中移除,那么他首先也会从内存中移除 children 。因此,例如,一个window被消去,window的所有组成部分也将被消去,即使它们不是它的直接children。

从上面可以得出结论,objective 是 QObjects,但是使用该逻辑 QWidget 也使用该层次结构进行绘制。

支持我的回答的另一个论据是setParent()方法需要一个QObject,而不是一个QWidget:所有QWidget都是一个QObject但不是所有QObject都是一个QWidget-