Issue
I'm trying to understand how nesting of layouts and widgets work so I took out all of the initializer arguments and used .setWhatever instead, .setParent, .setText, and so on. This worked except for the second and third of the QtWidgets.QVBoxLayout widgets; for the first one it's setting its parent to frame_main, and for the second and third ones it's setting it to frame_sensor. Both of those frame_ widgets are of type QtWidgets.QFrame. When the second and third QVBoxLayout widgets use setParent (frame_sensor) it produces the message "A layout can only have another layout as a parent" but if I instantiate that layout widget with QtWidgets.QVBoxLayout (frame_sensor) there's no complaint. Can someone explain why sometimes I can and sometimes I can't use .setParent or what's going wrong?
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()
Solution
There is no documentation that indicates one of the objectives of setParent()
is to establish a widget to which the layout will handle the geometry of its children. If you want to do this there are 2 options:
- Indicate it in the layout constructor.
layout_vbox = QtWidgets.QVBoxLayout(frame_sensor)
- Or use the QWidget's setLayout method.
layout_vbox = QtWidgets.QVBoxLayout()
frame_sensor.setLayout(layout_vbox)
The objective of setParent()
is to establish a hierarchy between the QObjects to be able to handle the memory of the children (the ownership) since Qt implements the creation of objects in the heap. So the logic is if the father is removed from memory then first he will remove the children from it as well. Thus, for example, a window is eliminated, all the components of the window will also be eliminated, even if they are not the direct children of it.
From the above it is concluded that the objective is the QObjects, but using that logic the QWidget also use that hierarchy for painting.
Another argument in favor of my answer is that the setParent()
method expects a QObject, not a QWidget: All QWidget is a QObject but not all QObject is a QWidget-
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.