- MySignal muss zwingend auf Exemplarebene liegen, nicht klassenweit (sonst werden die Signale dupliziert)
- MySignal braucht das Exemplar mit dem Signal als parent (sonst kann pyconnect nicht die korrekte Threadaffinität herausfinden)
Code: Alles auswählen
from PyQt4 import QtGui
from PyQt4.QtCore import pyqtSignal, QObject, QThread
class Wrapper(QObject):
def __init__(self, f):
QObject.__init__(self, None)
self.f = f
def wrap(self, *args):
print self.thread().currentThreadId(), 'should be equal to:',
return self.f(*args[0], **args[1])
class MySignal(QObject):
sig = pyqtSignal(tuple, dict)
def __init__(self, parent):
QObject.__init__(self, parent)
self.wrappers = []
def pyconnect(self, f):
wrapper = Wrapper(f)
if (f.im_self.thread() != self.thread()):
wrapper.moveToThread(f.im_self.thread())
self.wrappers.append(wrapper)
self.sig.connect(wrapper.wrap)
def connect(self, f):
self.sig.connect(f)
def emit(self, args, kwargs):
self.sig.emit(args, kwargs)
def pyemit(self, *args, **kwargs):
self.sig.emit(args, kwargs)
class Work(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.done = MySignal(self)
def work(self, a, b, c):
print self.thread().currentThreadId(), 'should be subthread'
self.done.pyemit('done', 'with', z='work')
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
# MySignal must be instance not class wide and must have parent set!
self.do = MySignal(self)
# some work for a thread
self.work = Work()
self.mythread = QThread(self)
self.work.moveToThread(self.mythread)
# signal for do work and work done
# always do signal slot connections after the thread binding
self.do.pyconnect(self.work.work)
self.work.done.pyconnect(self.done)
# start thread
self.mythread.start()
# some action to trigger everything
self.button = QtGui.QPushButton(self)
self.button.clicked.connect(lambda : self.do.pyemit('a', 'b', c='c'))
def done(self, x, y, z):
print self.thread().currentThreadId(), 'should be mainthread'
def closeEvent(self, ev):
# shutdown thread gracefully
self.mythread.quit()
self.mythread.wait()
if __name__ == '__main__':
app = QtGui.QApplication([])
print app.thread().currentThreadId(), 'mainthread'
win = Widget()
win.show()
app.exec_()