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-
我试图了解布局和小部件的嵌套是如何工作的,所以我取出了所有初始化参数并改用 .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-