meaulnes
meaulnes

Reputation: 383

Message says NonType object, but object is a QHBoxLayout

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.

enter image description here 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

Answers (1)

eyllanesc
eyllanesc

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

Related Questions