2014-06-11 59 views
2

我有一个用C++(逻辑)和QML(UI)编写的应用程序。 在C++部分我有QML对象(种事件系统的)C++ invokeMethod无法访问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)

什么我做错了?

回答

2

必须使用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)"

+0

好的,谢谢@Mitch!当我到达我的工作电脑时,我会尝试它。 所以你说这是不可能使用任何注册类型,但只能作为函数参数转换为QVariant? – folibis

+0

这可能是可能的;正如我所说,我不确定。 – Mitch

+0

我已经更新了我的答案,并解释了为什么QVariant是必要的。 – Mitch