2

I want to use QMetaObject::invokeMethod to call a method of an object (later it will run in another thread and then invokeMethod comes in handy). I use the Qt 4.8 bindings of PySide 1.2.1 on Python 3.3. The full example is:

from PySide import QtCore

class Tester(QtCore.QObject):
    def __init__(self):
        super().__init__()

    def beep(self):
        print('beep')

if __name__ == '__main__':
    t = Tester()
    QtCore.QMetaObject.invokeMethod(t, 'beep', QtCore.Qt.AutoConnection)

And the output is:

QMetaObject::invokeMethod: No such method Tester::beep()

while I expected beep. The method was not invoked.

So what's wrong? It seems so simple that I cannot find the error.


edit: I got it to work using the `@QtCore.Slot' decoration on the method. Thanks to the comment and the answer.

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
  • 1
    The beep() should be declared as a slot, no? – vahancho Apr 17 '14 at 08:21
  • Oh yes, that is the solution. Need to add `@QtCore.Slot()` in front of `def beep(self):`. I'm not used to it because for connecting signals now I exclusively just give him any callable and it works fine. It wasn't obvious one has to do it here but thanks for the comment. – NoDataDumpNoContribution Apr 17 '14 at 08:28

1 Answers1

4

You cannot invoke regular methods, only signals and slots. That is why it is not working for you. See the QMetaObject documentation for details about it:

Invokes the member (a signal or a slot name) on the object obj. Returns true if the member could be invoked. Returns false if there is no such member or the parameters did not match.

Try this decorator:

...
@QtCore.Slot()
def beep(self):
    print('beep')
...

See the following documentation for details as well as this one:

Using QtCore.Slot()

Slots are assigned and overloaded using the decorator QtCore.Slot(). Again, to define a signature just pass the types like the QtCore.Signal() class. Unlike the Signal() class, to overload a function, you don’t pass every variation as tuple or list. Instead, you have to define a new decorator for every different signature. The examples section below will make it clearer.

Another difference is about its keywords. Slot() accepts a name and a result. The result keyword defines the type that will be returned and can be a C or Python type. name behaves the same way as in Signal(). If nothing is passed as name then the new slot will have the same name as the function that is being decorated.

Community
  • 1
  • 1
László Papp
  • 51,870
  • 39
  • 111
  • 135
  • Thanks for the explanation. I extended the question a bit (by a parameter) and run into the same problem although using the Slot decorator. Do you have an idea what's wrong with the second code snippet from above? Is it the right decoration? – NoDataDumpNoContribution Apr 17 '14 at 08:56
  • `QMetaObject::invokeMethod: No such method Tester::beep(text)` but you have self in the declaration. I do not know the answer, but I would try to pass the Tester,t pair as a generic argument for a quick test. Failing that, you could move the method out of the class. – László Papp Apr 17 '14 at 09:22
  • You could also call a class method which does the invokemethod internally. – László Papp Apr 17 '14 at 09:27
  • Passing the Tester t as generic argument `QGenericArgument('self', t)` gives `No such method Tester::beep(self,text)` although in a sense this exactly the method I have. Move the methoud out of the class seems difficult because `QMetaObject::invokeMethod` seems to need an obj as first parameter. Will try the internal invokeMethod next. – NoDataDumpNoContribution Apr 17 '14 at 09:30
  • @Trilarion: other workaround is to set the string with a setter method, and use that in your slot. I know it is hacky, but that could also get you going. ;-) – László Papp Apr 17 '14 at 09:32
  • @LasloPapp: Internal calling made no difference. I wonder if invoking methods in Python and Qt with parameters is actually possible or not. If no other answer comes up here I would post to a PySide support forum and then report back here the answers. – NoDataDumpNoContribution Apr 17 '14 at 09:39
  • @Trilarion: python methods need to have the first argument dedicated to the class, but as a silly trial: could you remove the "self"? Perhaps they hacked it around somehow for pyside. Silly idea, but it does not take long to try... – László Papp Apr 17 '14 at 09:46
  • Not sure where exactly I should do it and what should be left. I tried a bit but to no avail. – NoDataDumpNoContribution Apr 17 '14 at 09:50
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/50885/discussion-between-trilarion-and-laszlo-papp) – NoDataDumpNoContribution Apr 17 '14 at 13:59