Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyQt5 GUI crashes when QTreeWidget is cleared

Tags:

python

pyqt5

When the # is removed from the line in the code below, why does the GUI crash when the button is clicked?

The line in the code is:

self.treeWidget.currentItemChanged.connect(self.current_selection)

from PyQt5 import QtWidgets

class Ui_Form(object):

    def setupUi(self, Form):

        Form.setWindowTitle("Test")
        Form.resize(600, 400)

        self.gridLayout = QtWidgets.QGridLayout(Form)

        self.treeWidget = QtWidgets.QTreeWidget(Form)
        self.treeWidget.setColumnCount(3)
        self.treeWidget.setHeaderLabels(['No.', 'Colour', 'Animal'])
        #self.treeWidget.currentItemChanged.connect(self.current_selection)

        self.buttonWidget1 = QtWidgets.QPushButton('Click1')
        self.buttonWidget1.clicked.connect(self.test1)

        self.gridLayout.addWidget(self.treeWidget, 0, 0)
        self.gridLayout.addWidget(self.buttonWidget1, 1, 0)

        self.populate()

    def test1(self):
        self.treeWidget.clear()

    def current_selection(self):
        item = self.treeWidget.currentItem()
        self.no = item.text(0)
        self.colour = item.text(1)
        self.animal = item.text(2)
        print(self.no, self.colour, self.animal)

    def populate(self):
        item = QtWidgets.QTreeWidgetItem(['1', 'Yellow', 'Dog'])
        self.treeWidget.addTopLevelItem(item)

        item = QtWidgets.QTreeWidgetItem(['2', 'Black', 'Cat'])
        self.treeWidget.addTopLevelItem(item)

        item = QtWidgets.QTreeWidgetItem(['3', 'Green', 'Frog'])
        self.treeWidget.addTopLevelItem(item)

        item = QtWidgets.QTreeWidgetItem(['4', 'Blue', 'Snail'])
        self.treeWidget.addTopLevelItem(item)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

If anyone can explain to me what is occurring, it'd be greatly appreciated.

like image 610
Matthew Avatar asked Dec 07 '25 06:12

Matthew


2 Answers

To answer the specific question: Why does the GUI crash?

This is due to new behaviour which was introduced with PyQt-5.5. To quote from the PyQt5 docs:

In PyQt v5.5 an unhandled Python exception will result in a call to Qt’s qFatal() function. By default this will call abort() and the application will terminate. Note that an application installed exception hook will still take precedence.

Fortunately, as the final sentence indicates, this new behaviour can be bypassed by installing an excepthook, which will allow your program to deal with unhandled exceptions in a more graceful manner.

As a bare minimum, the old behaviour of simply printing the traceback to stdout/stderr can be restored like this:

def except_hook(cls, exception, traceback):
    sys.__excepthook__(cls, exception, traceback)

if __name__ == "__main__":

    import sys
    sys.excepthook = except_hook

But obviously, displaying the error in some kind of message-box would be a far more preferrable way to inform the user that a problem has occurred.

like image 112
ekhumoro Avatar answered Dec 09 '25 18:12

ekhumoro


By default, if there is no selection, currentItem() is the first item in the tree.

When the button is clicked, self.treeWidget.clear() is called. All the items are removed from the tree widget, so there is no more a first item: the signal currentItemChanged is emitted.

If there is nothing in the tree, self.treeWidget.currentItem() will returns None. In current_selection, item is None, and that's why you get:

AttributeError: 'NoneType' object has no attribute 'text'

To fix this, you can test if item is None before proceeding further:

def current_selection(self):
    item = self.treeWidget.currentItem()
    if item is not None:
        self.no = item.text(0)
        self.colour = item.text(1)
        self.animal = item.text(2)
    ...
like image 28
Mel Avatar answered Dec 09 '25 18:12

Mel