C ++ invokeMethod无法访问QML方法

时间:2014-06-11 04:51:55

标签: qt qml qtquick2

我有一个用C ++(逻辑)和QML(UI)编写的应用程序。 在C ++部分,我有一个QML对象的集合(一种事件系统)

这是C ++对象的简化代码:

class Config : public QObject
{
Q_OBJECT
    Q_ENUMS(DataEvent)
public:

    enum DataEvent {
        DataEventUndefined = 0,
        DataEventDateChanged
    };

    ~Config();
    Q_INVOKABLE void registerToEvent (DataEvent event, QQuickItem *item)
    {
        p_dataListeners.insert(event,item);
    }

private:
    QMap<DataEvent,QQuickItem *> p_dataListeners;
}

在QML对象中我称之为C ++函数,它就像魅力一样。这是QML代码的一部分:

Item {
    id: myQMLObject
    function init() {
        Config.registerToEvent(Config.DataEventDateChanged,myQMLObject);
    }
    function receiveEvent(eventType) {
    ...
    }
}

好的,现在我想调用一个已保存的QML对象的QML函数:

    event = Config::DataEventDateChanged;
    QMapIterator<DataEvent,QQuickItem *> i(p_dataListeners);
    while (i.hasNext()) {
        i.next();
        if(event == i.key()) {
            QQuickItem *item = i.value();
            QMetaObject::invokeMethod(item, "receiveEvent",
                                      QGenericReturnArgument(),
                                      Q_ARG(Config::DataEvent, event));
        }
    }

但我收到此错误:QMetaObject::invokeMethod: No such method MyQMLObject_QMLTYPE_44::receiveEvent(Config::DataEvent)

我做错了什么?

1 个答案:

答案 0 :(得分:3)

您必须使用QVariant作为参数类型:

#include <QApplication>
#include <QtQuick>

class Thing : public QObject
{
    Q_OBJECT
    Q_ENUMS(DataEvent)
public:
    enum DataEvent {
        DataEventUndefined = 0,
        DataEventDateChanged
    };

    Thing() {}

public slots:
    void registerToEvent(QQuickItem *stuff) {
        DataEvent event = Thing::DataEventDateChanged;
        QMetaObject::invokeMethod(stuff,
            "receiveEvent",
            QGenericReturnArgument(),
//            Q_ARG(Thing::DataEvent, event));
            Q_ARG(QVariant, event));
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    Thing thing;
    engine.rootContext()->setContextProperty("thing", &thing);
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    return app.exec();
}

#include "main.moc"

<强> main.qml:

import QtQuick 2.2
import QtQuick.Window 2.0

Window {
    visible: true
    width: 300
    height: 250

    Item {
        id: item

        Component.onCompleted: {
            thing.registerToEvent(item);
        }

        function receiveEvent(arg) {
            print(arg);
        }
    }
}

这是因为QML中JavaScript函数的参数类型是QVariant。我们可以通过qmetaobject.cpp的一小部分来验证这一点:

diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index accefb1..e39539c 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -1455,6 +1455,10 @@ bool QMetaObject::invokeMethod(QObject *obj,
     }

     if (idx < 0 || idx >= meta->methodCount()) {
+        for (int i = 0; i < meta->methodCount(); ++i) {
+            QMetaMethod method = meta->method(i);
+            qDebug() << method.methodSignature();
+        }
         qWarning("QMetaObject::invokeMethod: No such method %s::%s",
                  meta->className(), sig.constData());
         return false;

当方法调用失败时,我们迭代moc已知对象的每个方法。通过上面的示例,输出:

"destroyed(QObject*)"
"destroyed()"
"objectNameChanged(QString)"
"deleteLater()"
"_q_reregisterTimers(void*)"
"childrenRectChanged(QRectF)"
"baselineOffsetChanged(double)"
"stateChanged(QString)"
"focusChanged(bool)"
"activeFocusChanged(bool)"
"activeFocusOnTabChanged(bool)"
"parentChanged(QQuickItem*)"
"transformOriginChanged(TransformOrigin)"
"smoothChanged(bool)"
"antialiasingChanged(bool)"
"clipChanged(bool)"
"windowChanged(QQuickWindow*)"
"childrenChanged()"
"opacityChanged()"
"enabledChanged()"
"visibleChanged()"
"visibleChildrenChanged()"
"rotationChanged()"
"scaleChanged()"
"xChanged()"
"yChanged()"
"widthChanged()"
"heightChanged()"
"zChanged()"
"implicitWidthChanged()"
"implicitHeightChanged()"
"update()"
"_q_resourceObjectDeleted(QObject*)"
"grabToImage(QJSValue,QSize)"
"grabToImage(QJSValue)"
"contains(QPointF)"
"mapFromItem(QQmlV4Function*)"
"mapToItem(QQmlV4Function*)"
"forceActiveFocus()"
"forceActiveFocus(Qt::FocusReason)"
"nextItemInFocusChain(bool)"
"nextItemInFocusChain()"
"childAt(double,double)"
"receiveEvent(QVariant)"

请注意最后一项"receiveEvent(QVariant)"