2014-06-11 102 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