Friday, January 29, 2010

PyQt: Emitting events from non-QObject subclasses.

In order to emit events in PyQt the emitting class must inherit directly from QObject. This can be quite a nuisance, especially so because multiple inheritance is impossible when using PyQt. E.g., I recently had the problem that I had task running in a QThreadPool that I would like to emit a signal when progress had been made, so that I could update a progressbar in my UI. To make the task runnable in a QThreadPool the task class had to inherit from QRunnable, and as QRunnable is not a subclass of QObject it was impossible to emit signals from within the task class. I found a solution to this problem though - one that I find quite elegant, so I'd like to share it with you :-)

The trick is to use another object as the mediator for emitting signals, and then using Python properties to hide the fact that a mediator is being used. Consider the example below:
class Mediator(QObject):
mySignal = pyqtSignal(int)
def __init__(self):
super(Mediator, self).__init__()

class Task(QRunnable):
def __init__(self):
super(Task, self).__init__()
self._mediator = Mediator()

def mySignal():
def fget(self):
return self._mediator.mySignal
return locals()
mySignal = property(**mySignal())
Using this approach any classes working with Task instances can connect directly to the mySignal signal as if it was bound directly to the Task class. So the property hides the fact that a mediator is in use.

No comments:

Post a Comment