Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
685 views
in Technique[技术] by (71.8m points)

python - QMetaObject::invokeMethod doesn't find methods with parameters

This is a follow up of QMetaObject::invokeMethod doesn't find the method. Invoking a method without paramters works. But extending the previous question to methods with parameters brings me back to failure again.

See the following example script in Python:

from PySide import QtCore

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

    @QtCore.Slot()
    def dup(self):
        beep('dup-class')

    @QtCore.Slot(str)
    def beep(self, text):
        print(text)

@QtCore.Slot()
def dup(self):
    beep('dup-local')

@QtCore.Slot(str)
def beep(text):
    print(text)

if __name__ == '__main__':
    QtCore.QMetaObject.invokeMethod(None, 'dup')
    QtCore.QMetaObject.invokeMethod(None, 'beep', QtCore.Qt.AutoConnection, QtCore.QGenericArgument('text', 'beep-local'))

    print('now some classy trials')
    t = Example()
    QtCore.QMetaObject.invokeMethod(t, 'dup')
    QtCore.QMetaObject.invokeMethod(t, 'beep', QtCore.Qt.AutoConnection, QtCore.QGenericArgument('text', 'beep-class'))
    QtCore.QMetaObject.invokeMethod(t, 'beep', QtCore.Qt.AutoConnection, QtCore.QGenericArgument('self', t), QtCore.QGenericArgument('text', 'beep-class-b'))

The output with PySide 1.2.1 and Python 3.3 on Windows 7 and Ubuntu 14.04 as well is:

now some classy trials
dup-class
QMetaObject::invokeMethod: No such method Example::beep(text)
QMetaObject::invokeMethod: No such method Example::beep(self,text)

This means that the invokeMethod calls to local methods failed silently. Only the call to Example:dup() gave the expected output. The two trials to get Example:beep(str) to work failed, although the failure messages give method signatures that actually should exist.

I posed an earlier version of this question on the PySide mailing list but it wasn't answered.

Question: How to make QMetaObject::invokeMethod calling local and class method with parameters in the Python Qt bindings (preferably in PySide)?

edit: By the way: if one knows what Signal:emit(...) or QtCore.QTimer.singleShot(0, ...) do under the hood, that could help here too. After all all these different approaches have very similar effects.


edit2:

With 'QString' as parameter name the warning messages disappear but Python fails as a whole with segfaults. It may be an implementation bug of PySide. The rule seems to be that one has to give the Qt-C++ types of the parameters in invokeMethod and the Python types in the Slots.

from PySide import QtCore

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

    @QtCore.Slot(str)
    def beep(self, text='default'):
        print(text)

if __name__ == '__main__':
    app = QtCore.QCoreApplication([])

    e = Example()
    QtCore.QMetaObject.invokeMethod(e, 'beep', QtCore.Qt.AutoConnection, QtCore.QGenericArgument('QString', 'beep'))

    QtCore.QTimer.singleShot(1000, app.quit)
    app.exec_()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For anybody still interested in this:

As of version 1.2.4, PySide is buggy in that it doesn't wrap the Q_ARG and Q_RETURN_ARG macros. Instead, it unwisely wraps the QGenericArgument and QGenericReturnArgument classes, which are internal helper classes and not meant to be instanciated directly. As a result of this, invoking slots with arguments invariably results in a segmentation fault.

By comparison, PyQt does wrap the macros rather than the classes, and does not suffer from the same problems.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...