Unsolved 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.htmlI 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_SlotsBasically 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.
-
- 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? - Show your
-
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()
-
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().
-
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.