Abel Vargas
Abel Vargas

Reputation: 47

PySide: Emiting signal from QThread in new syntax

I'm trying (and researching) with little success to emit a signal from a working Qthread to the main window. I don't seem to understand how I should go about this in the new syntax.

Here's a simple example.

from PySide.QtCore import *
from PySide.QtGui import *
import sys
import time

class Dialog(QDialog):

    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)

        button = QPushButton("Test me!")

        layout = QVBoxLayout()
        layout.addWidget(button)
        self.setLayout(layout)

        #self.button.clicked.connect(self.test) ----> 'Dialog' object has no attribute 'button'
        self.connect(button, SIGNAL('clicked()'), self.test)
        self.workerThread = WorkerThread()


    def test(self):
        self.workerThread.start()
        QMessageBox.information(self, 'Done!', 'Done.')


class WorkerThread(QThread):

    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)

    def run(self):
        time.sleep(5)
        print "Thread done!"


app = QApplication(sys.argv)
dialog = Dialog()
dialog.show()
app.exec_()

I understand that if I didn't have another thread I'd create the signal inside the Dialog class and connect it in the __init__ but how can I create a custom signal that can be emitted from WorkerThread and be used test()?

As a side question. You can see it commented out of the code that the new syntax for connecting the signal errors out. Is it something in my configurations?

I'm on OsX El Capitan, Python 2.7

Any help is highly appreciated! Thanks a lot

TL:DR: I'd like to emmit a signal from the WorkerThread after 5 seconds so that the test function displays the QMessageBox only after WorkingThread is done using the new syntax.

Upvotes: 1

Views: 734

Answers (1)

Abel Vargas
Abel Vargas

Reputation: 47

Ok, it's been a long day trying to figure this out. My main resource was this: http://www.matteomattei.com/pyside-signals-and-slots-with-qthread-example/

In the new syntax, in order to handle signals from different threads, you have to create a class for your signal like so:

class WorkerThreadSignal(QObject):
    workerThreadDone = Signal()

This is how the WorkerThread end up looking like:

class WorkerThread(QThread):

    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)
        self.workerThreadSignal = WorkerThreadSignal()

    def run(self):
        time.sleep(3)
        self.workerThreadSignal.workerThreadDone.emit()

And for the connections on the Dialog class:

    self.workerThread = WorkerThread()
    self.buttonn.clicked.connect(self.test)

and:

    self.workerThreadSignal = WorkerThreadSignal()
    self.workerThread.workerThreadSignal.workerThreadDone.connect(self.success)

def success(self):
    QMessageBox.warning(self, 'Warning!', 'Thread executed to completion!')

So the success method is called once the signal is emitted.

What took me the longest to figure out was this last line of code. I originally thought I could connect directly to the WorkerThreadSignal class but, at least in this case, it only worked once I backtracked it's location. From the Dialog init to WorkerThread init back to the WorkerThreadSignal. I took this hint from the website mentioned above.

I find strange that I have to create the same local variables on both classes, maybe there's a way to create one global variable I can refer to instead all the current solution but it works for now.

I hope this helps someone also stuck in this process!

PS: The syntax problem for the connection was also solved. So everything is written with the new syntax, which is great.

Upvotes: 2

Related Questions