[SOLVED] PyQt threading error while passing a signal to a QMessageBox



  • I tried to receive a string from a thread to my main GUI using SIGNALs. Everything works fine until I want to use the string in a QMessageBox. Printing out is no problem but starting a QMessageBox gives me several errors (some are about QPixmap which I even do not use in the GUI.

    Here is a short working example of my code:

    @import sys
    import urllib2
    import time
    from PyQt4 import QtCore, QtGui

    class DownloadThread(QtCore.QThread):
    def init(self):
    QtCore.QThread.init(self)

    def run(self):
        time.sleep(3)
        self.emit(QtCore.SIGNAL("threadDone(QString)"), 'test')
    

    class MainWindow(QtGui.QWidget):
    def init(self):
    super(MainWindow, self).init()
    self.list_widget = QtGui.QListWidget()
    self.button = QtGui.QPushButton("Start")
    self.button.clicked.connect(self.start_download)
    layout = QtGui.QVBoxLayout()
    layout.addWidget(self.button)
    layout.addWidget(self.list_widget)
    self.setLayout(layout)

        self.downloader = DownloadThread()
        self.connect(self.downloader, QtCore.SIGNAL("threadDone(QString)"), self.threadDone, QtCore.Qt.DirectConnection)
    
    def start_download(self):
        self.downloader.start()
    
    def threadDone(self, info_message):
        print info_message
        QtGui.QMessageBox.information(self,
                    u"Information",
                    info_message
                    )
        #self.show_info_message(info_message)
    

    if name == "main":
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.resize(640, 480)
    window.show()
    sys.exit(app.exec_())@

    I'm getting this erros:

    QObject::setParent: Cannot set parent, new parent is in a different thread
    QPixmap: It is not safe to use pixmaps outside the GUI thread

    This error only while moving the mouse and QMessageBox is still open:

    QObject::startTimer: timers cannot be started from another thread
    QApplication: Object event filter cannot be in a different thread.

    Can anyone tell me what I'm doing wrong?
    This is the first time I'm using threads.

    Thank you!
    Stefanie


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    You are imposing a direct connection which means the slot will be called from your thread context and doing GUI related stuff in another thread than the GUI thread is wrong.

    Either use a QueuedConnection or let Qt decide of the connection type

    Hope it helps



  • Hi!

    Thank you very much for the answer and nice welcome!
    It worked like charm and solved the problem!

    Cheers,
    Stefanie


  • Lifetime Qt Champion

    You're welcome !

    Since it's working now, can you update the thread's title to solved ? So other forum users may know a solution has been found :)



  • Its also worth noting that the way in which PyQt handles signals has changed so, rather than using strings to specify signals and there arguments, you can do it in a a clearer, more pythonic way as follows:

    • To Connect:
      <source_object>.<signal_name>.connect(<target_object>.<slot>)
    • To Emit:
      <source_object>.<signal_name>.emit(<arguments>)

    So, your example from above would read:

    @
    import sys
    import time
    from PyQt4 import QtCore, QtGui

    class DownloadThread(QtCore.QThread):
    def init(self):
    QtCore.QThread.init(self)

    def run(self):
        time.sleep(3)
        self.threadDone.emit('test')
    

    class MainWindow(QtGui.QWidget):
    def init(self):
    super(MainWindow, self).init()
    self.list_widget = QtGui.QListWidget()
    self.button = QtGui.QPushButton("Start")
    self.button.clicked.connect(self.start_download)
    layout = QtGui.QVBoxLayout()
    layout.addWidget(self.button)
    layout.addWidget(self.list_widget)
    self.setLayout(layout)

        self.downloader = DownloadThread()
        self.downloader.threadDone.connect(self.threadDone)
    
    def start_download(self):
        self.downloader.start()
    
    def threadDone(self, info_message):
        print info_message
        QtGui.QMessageBox.information(self,
                    u"Information",
                    info_message
                    )
    

    if name == "main":
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.resize(640, 480)
    window.show()
    sys.exit(app.exec_())
    @

    See "here":http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html for more info.

    Also, to further SGaists comment, its very rarely necessary to specify the connection type when connecting signals and slots, let PyQt/Qt select the most appropriate.

    Hope this helps ;o)



  • @SGaist
    Done!

    @
    Thank you very much for your suggestion, I'll change it!

    This forum is great! I want to switch from wxPython to PyQt and it is great to have such a good support! Just started to implement my software and I'm very surprised that everything works out of the box, especially switching all the time between Windows and Unix OS.

    Thanks again!
    Stefanie


  • Lifetime Qt Champion

    That's what Qt does :) (no I don't forget the bugs but nothing's perfect)



  • At least thousands times better then what I did up to now.
    It's took me several month to decide which framework to use for the change but I think I took the right one. Not sorry up to now.

    Sorry for off-topic. I'm just astonished how easy live can be.

    Greetings from Germany!
    Stefanie


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.