Reputation: 581
I've a Widget, which wants to display Images with QLabel
and QCheckBox
. 4 classes are created each contains some information to be put on the final screen.
Class Grid
align and grid images, text and checkboxes.
After script running get current screen. No images appear in present widget.
Where are images?
Desired screen
The code
import sys, os
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
class ImageWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
self.hlay = QtWidgets.QHBoxLayout(self)
buckling_ilabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/fixed-fixed.png"))
buckling_ilabel.resize(150, 150)
buckling_ilabel.setPixmap(pixmap.scaled(buckling_ilabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_ilabel)
buckling_blabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/pinned-pinned.png"))
buckling_blabel.resize(150, 150)
buckling_blabel.setPixmap(pixmap.scaled(buckling_blabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_blabel)
buckling_clabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/fixed-free.png"))
buckling_clabel.resize(150, 150)
buckling_clabel.setPixmap(pixmap.scaled(buckling_clabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_clabel)
buckling_dlabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/fixed-pinned.png"))
buckling_dlabel.resize(150, 150)
buckling_dlabel.setPixmap(pixmap.scaled(buckling_dlabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_dlabel)
self.setLayout(self.hlay)
class EffLengthInfo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(EffLengthInfo, self).__init__(parent)
ilabel = QtWidgets.QLabel('Ley = 1.0 L\nLec = 1.0 L')
blabel = QtWidgets.QLabel('Ley = 0.699 L\nLec = 0.699 L')
clabel = QtWidgets.QLabel('Ley = 2.0 L\nLec = 2.0 L')
dlabel = QtWidgets.QLabel('Ley = 0.5 L\nLec = 0.5 L')
self.ilay = QtWidgets.QHBoxLayout()
self.ilay.addWidget(ilabel)
self.ilay.addWidget(blabel)
self.ilay.addWidget(clabel)
self.ilay.addWidget(dlabel)
class CheckInfo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(CheckInfo, self).__init__(parent)
icheck = QtWidgets.QCheckBox()
bcheck = QtWidgets.QCheckBox()
ccheck = QtWidgets.QCheckBox()
dcheck = QtWidgets.QCheckBox()
self.checklay = QtWidgets.QHBoxLayout()
self.checklay.addWidget(icheck, alignment=QtCore.Qt.AlignCenter)
self.checklay.addWidget(bcheck, alignment=QtCore.Qt.AlignCenter)
self.checklay.addWidget(ccheck, alignment=QtCore.Qt.AlignCenter)
self.checklay.addWidget(dcheck, alignment=QtCore.Qt.AlignCenter)
class Grid(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Grid, self).__init__(parent)
self.imagewidget = ImageWidget()
self.efflengthinfo = EffLengthInfo()
self.checkinfo = CheckInfo()
vlay = QtWidgets.QVBoxLayout(self)
vlay.addLayout(self.imagewidget.hlay)
vlay.addLayout(self.efflengthinfo.ilay)
vlay.addLayout(self.checkinfo.checklay)
self.setLayout(vlay)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
im = Grid()
im.show()
sys.exit(app.exec_())
Upvotes: 4
Views: 5801
Reputation: 243897
The @S.Nick's solution works but it is not the correct one, besides that it does not explain the problem and it only indicates the error message that you should have provided.
The first mistake you have is that you do not have a consistent design, for example, even though a widget is a visual element, it does not only mean that it is only, it also has associated data, so I ask myself: Why did you create the ImageWidget
class, the same thing? for EffLengthInfo
and CheckInfo
? Well it seems that just to create a layout, is it necessary to create a widget to just create a layout? No, because the widget is an unnecessary resource, that is, wasted memory. Therefore, I point out that S.Nick's solution is incorrect since he is inviting others to overlap a design error.
If your goal is just to create layouts then better use a function:
import sys, os
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
def create_image_layout():
hlay = QtWidgets.QHBoxLayout()
for icon_name in ("images/fixed-fixed.png",
"images/pinned-pinned.png",
"images/fixed-free.png",
"images/fixed-pinned.png"):
label = QtWidgets.QLabel()
pixmap = QtGui.QPixmap(os.path.join(iconroot, icon_name))
label.resize(150, 150)
label.setPixmap(pixmap.scaled(label.size(), QtCore.Qt.KeepAspectRatio))
hlay.addWidget(label)
return hlay
def create_EffLengthInfo_layout():
hlay = QtWidgets.QHBoxLayout()
for text in ('Ley = 1.0 L\nLec = 1.0 L',
'Ley = 0.699 L\nLec = 0.699 L',
'Ley = 2.0 L\nLec = 2.0 L',
'Ley = 0.5 L\nLec = 0.5 L'):
label = QtWidgets.QLabel(text)
hlay.addWidget(label)
return hlay
def create_checkInfo_layout():
hlay = QtWidgets.QHBoxLayout()
for _ in range(3):
checkbox = QtWidgets.QCheckBox()
hlay.addWidget(checkbox, alignment=QtCore.Qt.AlignCenter)
return hlay
class Grid(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Grid, self).__init__(parent)
image_lay = create_image_layout()
efflengthinfo_lay = create_EffLengthInfo_layout()
checkinfo_lay = create_checkInfo_layout()
vlay = QtWidgets.QVBoxLayout(self)
vlay.addLayout(image_lay)
vlay.addLayout(efflengthinfo_lay)
vlay.addLayout(checkinfo_lay)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
im = Grid()
im.show()
sys.exit(app.exec_())
Why was it shown in the case of EffLengthInfo and CheckInfo "works"?
I point out that it works in quotes because it works but it is not the solution, going to the point, a layout is established in a layout and it is part of the widget and after that it can not be placed in another widget, and if we check ImageWidget
we see that you have established two times the layout to the widget:
class ImageWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
self.hlay = QtWidgets.QHBoxLayout(self) # 1.
...
self.setLayout(self.hlay) # 2.
When you set a widget when building the layout, it is set in that widget.
When the widget sets the layout using the setLayout()
method
Therefore you should throw the following error in the line vlay.addLayout(self.imagewidget.hlay)
:
QLayout::addChildLayout: layout "" already has a parent
Another solution is to set the widgets instead of the layouts:
class ImageWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
self.hlay = QtWidgets.QHBoxLayout(self)
...
# self.setLayout(self.hlay) # comment this line
class EffLengthInfo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(EffLengthInfo, self).__init__(parent)
...
self.ilay = QtWidgets.QHBoxLayout(self) # <-- add self
class CheckInfo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(CheckInfo, self).__init__(parent)
...
self.checklay = QtWidgets.QHBoxLayout(self) # <-- add self
class Grid(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Grid, self).__init__(parent)
self.imagewidget = ImageWidget()
self.efflengthinfo = EffLengthInfo()
self.checkinfo = CheckInfo()
vlay = QtWidgets.QVBoxLayout(self)
vlay.addWidget(self.imagewidget) # <-- change addLayout() to addWidget()
vlay.addWidget(self.efflengthinfo) # <-- change addLayout() to addWidget()
vlay.addWidget(self.checkinfo) # <-- change addLayout() to addWidget()
...
Another perspective that you might think, and this depends on the use you want to give the widget, is that you want an information unit to be an image, a text and a checkbox, so if it is correct to create a widget:
import sys, os
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
class FooWidget(QtWidgets.QWidget):
def __init__(self, path_icon, text, checked=False, parent=None):
super(FooWidget, self).__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, path_icon))
pixmap_label = QtWidgets.QLabel()
pixmap_label.resize(150, 150)
pixmap_label.setPixmap(pixmap.scaled(pixmap_label.size(), QtCore.Qt.KeepAspectRatio))
text_label = QtWidgets.QLabel(text)
checkbox = QtWidgets.QCheckBox(checked=checked)
lay.addWidget(pixmap_label)
lay.addWidget(text_label)
lay.addWidget(checkbox)
class Grid(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Grid, self).__init__(parent)
lay = QtWidgets.QHBoxLayout(self)
icons = ["images/fixed-fixed.png",
"images/pinned-pinned.png",
"images/fixed-free.png",
"images/fixed-pinned.png"]
texts = ["Ley = 1.0 L\nLec = 1.0 L",
"Ley = 0.699 L\nLec = 0.699 L",
"Ley = 2.0 L\nLec = 2.0 L",
"Ley = 0.5 L\nLec = 0.5 L"]
for path_icon, text in zip(icons, texts):
w = FooWidget(os.path.join(iconroot, path_icon), text)
lay.addWidget(w)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
im = Grid()
im.show()
sys.exit(app.exec_())
Upvotes: 3
Reputation: 13651
Line: vlay.addLayout (self.imagewidget.hlay)
error is: QLayout :: addChildLayout: layout "" already has a parent
Try it:
import sys, os
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
class ImageWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
# self.hlay = QtWidgets.QHBoxLayout(self)
self.hlay = QtWidgets.QHBoxLayout() # < --- -self
buckling_ilabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
buckling_ilabel.resize(150, 150)
buckling_ilabel.setPixmap(pixmap.scaled(buckling_ilabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_ilabel)
buckling_blabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
buckling_blabel.resize(150, 150)
buckling_blabel.setPixmap(pixmap.scaled(buckling_blabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_blabel)
buckling_clabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
buckling_clabel.resize(150, 150)
buckling_clabel.setPixmap(pixmap.scaled(buckling_clabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_clabel)
buckling_dlabel = QtWidgets.QLabel(self)
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
buckling_dlabel.resize(150, 150)
buckling_dlabel.setPixmap(pixmap.scaled(buckling_dlabel.size(), QtCore.Qt.KeepAspectRatio))
self.hlay.addWidget(buckling_dlabel)
# self.setLayout(self.hlay) # < ---
class EffLengthInfo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(EffLengthInfo, self).__init__(parent)
ilabel = QtWidgets.QLabel('Ley = 1.0 L\nLec = 1.0 L')
blabel = QtWidgets.QLabel('Ley = 0.699 L\nLec = 0.699 L')
clabel = QtWidgets.QLabel('Ley = 2.0 L\nLec = 2.0 L')
dlabel = QtWidgets.QLabel('Ley = 0.5 L\nLec = 0.5 L')
self.ilay = QtWidgets.QHBoxLayout()
self.ilay.addWidget(ilabel)
self.ilay.addWidget(blabel)
self.ilay.addWidget(clabel)
self.ilay.addWidget(dlabel)
class CheckInfo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(CheckInfo, self).__init__(parent)
icheck = QtWidgets.QCheckBox()
bcheck = QtWidgets.QCheckBox()
ccheck = QtWidgets.QCheckBox()
dcheck = QtWidgets.QCheckBox()
self.checklay = QtWidgets.QHBoxLayout()
self.checklay.addWidget(icheck, alignment=QtCore.Qt.AlignCenter)
self.checklay.addWidget(bcheck, alignment=QtCore.Qt.AlignCenter)
self.checklay.addWidget(ccheck, alignment=QtCore.Qt.AlignCenter)
self.checklay.addWidget(dcheck, alignment=QtCore.Qt.AlignCenter)
class Grid(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Grid, self).__init__(parent)
self.imagewidget = ImageWidget()
self.efflengthinfo = EffLengthInfo()
self.checkinfo = CheckInfo()
vlay = QtWidgets.QVBoxLayout(self)
vlay.addLayout(self.imagewidget.hlay) # < ---
# Error: QLayout::addChildLayout: layout "" already has a parent # < ---
vlay.addLayout(self.efflengthinfo.ilay)
vlay.addLayout(self.checkinfo.checklay)
self.setLayout(vlay)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
im = Grid()
im.show()
sys.exit(app.exec_())
Upvotes: 0