shyuu
shyuu

Reputation: 123

Statusbar doesn't show message immediately and sometimes crash

I created an interface in pyqt4 designer, there is only a button and a status bar. I want to show a message in the status bar when I click the button. For some reason I have to put this action in a new thread.

But when I click the button, nothing happened. The message didn't appear until I drag the edge of the window. Sometimes the click action even cause the program to crash:

pythonw.exe has stopped working.

This happens frequently, especially when I click too fast.

Here is my code:

from PyQt4 import QtCore, QtGui
import threading

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):

    def cal(self):
        self.statusbar.showMessage('something')   

    def onbutton(self):

        thread = threading.Thread(target=self.cal)
        thread.start()



    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(510, 409)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(170, 100, 171, 91))
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        self.pushButton.clicked.connect(self.onbutton)

        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.pushButton.setText(_translate("MainWindow", "PushButton", None))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Upvotes: 0

Views: 1378

Answers (1)

three_pineapples
three_pineapples

Reputation: 11849

The crash happens because you are interacting with the Qt GUI from a secondary thread. You are only allowed to interact with the GUI from the main thread (see the Qt documentation).

You have two options:

  1. Switch to a PyQt QThread, and emit a signal from the thread. If the signal is connected to a slot in the main thread, then you can do the GUI interaction there. This question/answer demonstrates approximately how to do this.

  2. Use QApplication.postEvent() to send an event from the Python thread to the main thread, which then causes a method to be run which interacts with the GUI. Note that some people have concerns that this is not OK (see this SO Answer), however I've had no issue with it. I've wrapped this up in an freely available library called qtutils (documentation here).

Upvotes: 4

Related Questions