PySide passing signals from QThread to a slot in a

2019-02-20 14:28发布

问题:

I solved my issue by moving the mySubQThread run() into the myQThread run()

That said, I still would like to know why what I was attempting before didn't work.

I'm pretty new to threading. I am running into this issue and I think I may be approaching things wrong, anyway here goes. I am open to a different approach I know this may be a bit convoluted to follow.

I have a GUI that makes a new derived QThread lets call it myQThread within that thread, I am running through a process that creates another thread call it mySubQThread the issue I am having is as follows, I have signals defined in my GUI for example: signalA = QtCore.Signal(int) and a slot in myQThread The slot in the mySubQThread never seems to get the signal.

Here is a working example. (modified somewhat)

from PySide import QtCore, QtGui
import time



class myQThread(QtCore.QThread):
    myThreadSignal = QtCore.Signal(int)
    def __init__(self, parent):
        super(myQThread, self).__init__(parent=parent)

    def run(self):
        self.subThread = mySubQThread(parent=self)
        self.myThreadSignal.connect(self.subThread.sub_thread_slot)
        self.myThreadSignal.connect(self.test_slot)
        print "starting subthread..."
        self.subThread.start()

        while self.subThread.isRunning():
            print "myQThread is alive!"
            time.sleep(1)
        print "myQThread exiting run..."
    @QtCore.Slot(int)
    def my_thread_slot(self, a):
        print "1b) Made it here!"
        self.myThreadSignal.emit(a)

    @QtCore.Slot(int)
    def test_slot(self, a):
        print "2a) Made it here!"

class mySubQThread(QtCore.QThread):
    mySubSignalA = QtCore.Signal(int)
    def __init__(self, parent):
        super(mySubQThread, self).__init__(parent=parent)
        self._abort = False
    def run(self):
        #Do some processing
        #Wait for signal
        self._abort = False
        while not self._abort:
            print "mySubQThread is alive!"
            time.sleep(1)
        print "mySubQThread exiting run..."

    @QtCore.Slot(int)
    def sub_thread_slot(self, a):
        print "2b)Never make it here!"
        self._abort = True


class myWidget(QtGui.QWidget):
    myWidgetSignal = QtCore.Signal(int)
    def __init__(self, parent=None):
        super(myWidget, self).__init__(parent=parent)
        #simple Widget to test this out....
        myLayout = QtGui.QVBoxLayout()
        self.runButton = QtGui.QPushButton("run")
        self.runButton.clicked.connect(self.run_button_pressed)

        self.otherButton = QtGui.QPushButton("other")
        self.otherButton.clicked.connect(self.other_button_pressed)

        myLayout.addWidget(self.runButton)
        myLayout.addWidget(self.otherButton)

        self.setLayout(myLayout)
    @QtCore.Slot()
    def run_button_pressed(self):
        self.processThread = myQThread(self)
        self.myWidgetSignal.connect(self.processThread.my_thread_slot)
        self.myWidgetSignal.connect(self.test_slot)
        self.processThread.start()
    @QtCore.Slot()
    def other_button_pressed(self):
        self.myWidgetSignal.emit(1)

    @QtCore.Slot(int)
    def test_slot(self, a):
        print "1a) Made it here!"

if __name__ == "__main__":
    import sys
    myApp = QtGui.QApplication(sys.argv)
    myWin = myWidget()
    myWin.show()
    sys.exit(myApp.exec_())

Here is some sample output:

Note that if you change the line:

        self.subThread = mySubQThread(parent=self)

to

        self.subThread = mySubQThread(parent=None)

it stops complaining as it does in the sample output. neither shows that it makes it to 2B

QObject: Cannot create children for a parent that is in a different thread.
(Parent is myQThread(0x3c3faf0), parent's thread is QThread(0x2792548), current thread is myQThread(0x3c3faf0)
starting subthread...
myQThread is alive!mySubQThread is alive!

mySubQThread is alive!
myQThread is alive!
1b) Made it here!
2a) Made it here!
1a) Made it here!

回答1:

The problem is because you have overridden QThread.run(). The run method by default contains an implementation that handles signal processing.

If you want to use signals/slots correctly you should subclass QObject, put your code in a method in there, and use moveToThread() to move the QObject to a base instance of QThread that you instantiate. You can then run your code by connecting your method to the QThread.started signal and then calling thread.start()

You can then repeat the creation of the child thread in a similar way, by putting that code in the method of the QObject previously created and launched in the thread. Signals and slots you connect there will be made between the thread and it's child thread correctly.

This is a good example of proper communication between the main thread and a QThread, but you could easily extend it to between QThreads. Just modify the MyWorker.firstWork() method to launch a new QThread like is already done in the setupThread method.