简体   繁体   中英

PyQt5 GUI crashes when QTreeWidget is cleared

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.

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.

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)
    ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM