Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Slots with no types



  • Hi guys,

    Apologies, this is kind of a basic issue with Qt for Python but I couldn't find much online.
    I want to make a Q_INVOKABLE equivalent for Python, with no arguments.

    In this page, it says there is no Q_INVOKABLE in PySide2, I need to use Slot.
    https://doc.qt.io/qtforpython-5.12/extras/PySide.QtCore.Slot.html

    I managed to get it working when using a parameter, such as

    @Slot(int)
    def update(self, num):
        self.set_test(str(datetime.now()))
    

    However as you can see, that was using a "dummy" int, most of the time I want to call the Slot without arguments.
    All slots used in the examples I can find use parameters: https://wiki.qt.io/Qt_for_Python_Signals_and_Slots

    Basically I want to do this:

    @Slot
    def update(self):
        self.set_test(str(datetime.now()))
    

    But the error in that case, when it applies the Slot decorator, is:

    Exception has occurred: TypeError
    Unknown signal argument type: function
    

    What's the way around this? Is there like a "void" type I can add to the decorator to make the Slot able to work with no arguments?

    Thanks.



  • @james2048

    • Show your connect() statement.
    • What is wrong then with:
    @Slot(int)
    def update(self):
        self.set_test(str(datetime.now()))
    

    So you declare the slot as taking a parameter but omit that from the def line?



  • Hi Jon8,

    I can't declare it as Slot taking an int without matching the signature, because the decorator catches it as an error (mismatching method types).
    I am not using connect() here: a couple more details.
    I am trying to call the method from QML. Usually in C++ I would mark the method as Q_INVOKABLE and then QML is able to find it and call it.

    I create a QObject subclass which contains the Slot:

    class ViewModel(QObject):
        test_changed = Signal()
        property_changed = Signal(str)
    
        def get_test(self):
            return self._test
    
        def set_test(self, val):
            self._test = val
            self.test_changed.emit()
            self.property_changed.emit("test")
    
        test = Property(str, get_test, set_test, notify=test_changed)
    
        def __init__(self):
            QObject.__init__(self)
            self.update(0)
    
        # Here is the Slot I'd like to be able to declare without arguments.
        @Slot(int)
        def update(self, dummy):
            self.set_test(str(datetime.now()))
    

    I instantiate it and register it to the QML engine:

    vm = ViewModel()
    engine.rootContext().setContextProperty("viewModel", vm)
    

    Then I use it from here in the QML (rest of layout ommitted):

    Text {
        text: viewModel.test
    }
    
    Button {
        text: "Update"
        onClicked: viewModel.update(0)
    }
    

    So ideally I'd like not to have to write update(0) or insert a dummy value and so on when I don't need the parameter.
    Is that possible at all? I must be missing something.

    Thanks.



  • I found the way to do it.
    I was sure this was able to be expressed in PySide2!

    I looked at the .pyi file and I saw it is looking for a list of types as arguments, with no default arguments.
    So I tried putting "None" as the argument to it, and it worked.
    Ideally if they had a default argument one could just write @Slot but for now this is needed. Maybe I could write in the bug tracker as an improvement.

    Now this works:

    @Slot(None)
    def update(self):
        self.set_test(str(datetime.now()))
    

    And now this QML also works:

    onClicked: viewModel.update()
    

  • Lifetime Qt Champion

    Hi,

    AFAIR, just use @Slot() and you should be good to go. This is a parametrized decorator, you can't just remove the parenthesis.



  • @SGaist
    Thanks, this exposes a preconception I had about Python decorators! I though @Slot == @Slot() and this is obviously not right.

    It does work with @Slot().


  • Lifetime Qt Champion

    Indeed they are different, one takes parameters and the other does not. But even if you have all parameters with default values, you can not bypass the use of the parenthesis for proper initialization.


Log in to reply