Reputation: 383
I am new to PyQt and I encounter a rather difficult (to me) problem.
I have a QVBoxLayout. I populate it dynamically with several QHBoxLayout. Each QHBoxLayout host, in this order, 3 QLineEdit, 1 QLabel and 1 QPushButton.
The button on the right is connected to the function remove_malt whose code is given below :
def add_malt(self):#call when clicking on a push button
maltT=self.s[str(self.malt_list_widget.currentItem().text())]
self.listMalts.append(maltT)
h_layout=QtGui.QHBoxLayout()#create an horizontal layout to host widgets for one malt line
h_layout.addWidget(QtGui.QLineEdit(maltT.full_name))#for grain full name
h_layout.addWidget(QtGui.QLineEdit())#for percentage
h_layout.addWidget(QtGui.QLineEdit())#for calculated mass
h_layout.addWidget(QtGui.QLabel('kg'))#for unit
h_layout.addWidget(QtGui.QPushButton('X')) #for deletion
h_layout.itemAt(0).widget().setMinimumSize(400,30)
h_layout.itemAt(0).widget().setStyleSheet("font-size: 14px;background-color: rgb(230, 230, 230);")
h_layout.itemAt(0).widget().setReadOnly(True)
h_layout.itemAt(1).widget().setMaximumSize(50,30)
h_layout.itemAt(1).widget().setStyleSheet("font-size: 14px;background-color: white;")
h_layout.itemAt(1).widget().textEdited.connect(self.clean_results)
h_layout.itemAt(2).widget().setMaximumSize(70,30)
h_layout.itemAt(2).widget().setStyleSheet("font-size: 14px;background-color: rgb(230,230,0) ;")
h_layout.itemAt(2).widget().setReadOnly(True)
h_layout.itemAt(3).widget().setMaximumSize(50,30)
h_layout.itemAt(3).widget().setStyleSheet("font-size: 14px;")
h_layout.itemAt(4).widget().setMaximumSize(30,30)
h_layout.itemAt(4).widget().setStyleSheet("font-size: 14px;color: 'red';background-color: rgb(230,230,230);font-weight: bold; ")
h_layout.itemAt(4).widget().clicked.connect(self.remove_malt)
self.grainLayout.addLayout(h_layout)
def remove_malt(self):
s= self.sender()
for i in range(self.grainLayout.count()):
#if i==0:
# continue
print('loop '+str(i))
#pb=self.grainLayout.itemAt(i).layout().itemAt(4).widget()
ly=self.grainLayout.itemAt(i).layout()
print ('voici ly')
print (ly)
pb=ly.itemAt(4).widget()
if s ==pb:
print('delete '+str(i))
self.clearLayout(self.grainLayout.itemAt(i).layout())
del self.listMalts[i]
return
def clearLayout(self,layout):
print(layout)
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
else :
self.clearLayout(item.layout())
The wrapping QVBoxLayout is called grainLayout and the text above is not part of it. I volontarily broke the line`#pb=self.grainLayout.itemAt(i).layout().itemAt(4).widget() in order to be able to print the value of ly (layout) which is the source of the pb.
I can remove some of the lines (QHBoxLayout) but at some moment, sometime at the last one, some other time at a random position,something wrong happens. Here is the content of the console
loop 0
voici ly
<PyQt4.QtGui.QHBoxLayout object at 0x7faef91e06d8>
delete 0
<PyQt4.QtGui.QHBoxLayout object at 0x7faef91e06d8>
loop 0
voici ly
<PyQt4.QtGui.QHBoxLayout object at 0x7faef91e06d8>
Traceback (most recent call last):
File "/home/jaaf/beer/MassCalculationWindow.py", line 122, in remove_malt
pb=ly.itemAt(4).widget()
AttributeError: 'NoneType' object has no attribute 'widget'
line 122 is the line where pb is evaluated
Reading this, it seems that at the moment of the pb 'NonType object has no attribute 'widget' ly is exactly the same object as before, I mean a QHBoxLayout.
Please, I need help.
Upvotes: 1
Views: 480
Reputation: 243945
In your code you must remove the items, in addition to removing the widgets, besides verifying that the item exists.
Remark: if obj is not None:
is equal to if obj:
def remove_malt(self):
s= self.sender()
for i in range(self.grainLayout.count()):
item =self.grainLayout.itemAt(i)
if item:
if s == item.layout().itemAt(4).widget():
self.clearLayout(item.layout())
self.grainLayout.removeItem(item)
del self.listMalts[i]
return
def clearLayout(self, layout):
if layout:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
else :
self.clearLayout(item.layout())
layout.removeItem(item)
Upvotes: 1