Question

I have a problem using Qt signal/slot mechanism in PySide when I want to send None.

Suppose I have a class named Calculator (a subclass of QObject) that can perform certain calculations the result of which can be anything, i.e. any type of Python object or even None. I need the instances of Calculator class to be able to signal the result to some consumer objects (subclasses of QObject).

What I had:

class Calculator(QObject):
    finished = PySide.QtCore.Signal(object)  # object means it can transmit anything

    def calc(self):
        ... # calculation of the result
        self.finished.emit(result)

class Consumer(QObject):
    def __init__(self, calculator):
        ...
        calculator.finished.connect(self.consume)

    def consume(self, result):  # do something with the result
        ...

This works fine except the situation when result is None. Then the program crashes when emitting the signal. It seems as if None is not a Python object (which may be true, I am not that proficient in the language standards).

Now I have a workaround, using two signals:

    finished = PySide.QtCore.Signal((),(object,))

and:

    def calc(self):
        ... # calculation of the result
        if result is None:
            self.finished.emit()
        else:
            self.finished[object].emit(result)

This solution works but it is complicated because it requires the consumer objects to link the signal twice. Either to two slots or to one slot with one default argument equal to None.

class Consumer(QObject):
    def __init__(self, calculator):
        ...
        calculator.finished.connect(self.consume)
        calculator.finished[object].connect(self.consume)

    def consume(self, result=None):  # do something with the result
        ...

This is complicated and prone to errors when creating many different consumer classes. I think this problem is the same with PyQt, with the difference that alternative signals are defined using lists [], [object] rather than tuples (),(object,).

My question is: is there any simple solution to this problem? Ideally with just one signal?

Was it helpful?

Solution

As an aside, this bug still exists in PySide where it segfaults on the transmission of a None signal as of version 1.2.1 (has existed since 1.1.0). There is a bug report at:

https://bugreports.qt-project.org/browse/PYSIDE-17

Obviously V.K.'s solution of encapsulating the None within a separate class still works, as does choosing another type to transmit instead (I switched my None to float('nan')). I just wanted to update this as I ran into the same issue and found this, and later the bug report explaining the segfault.

OTHER TIPS

Just after posting my problem I found an answer. So I appologize for answering my own question - I know it is not how it should be on StackOverflow. I created a class named ResultHolder which encapsulates the real result (result is a member variable of this class). Then I am transmitting instances of this ResultHolder class. The rest of the solution is then just straightforward.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top