QML和 C++對象可以通過,signals,slots和 屬性修改進行交互。對於一個C++對象,任何數據都可以通過Qt的 Meta-Object System暴露給QML(何總方法,後面介紹),同時,任何的QML對象數據通過Meta-object system在C++端直接訪問。
在實際的項目中很多地方會用到QML與Qt C++交互。在這裡總結了若干方法供大家參考,歡迎大家指導和拍磚。
在這裡不外乎有三種方法:
1. 把Qt C++中的對象或類型暴露給 QML端,供QML端使用。(官方說法是“嵌入”而非“暴露”,比較文明。- -b)
2. QML中的Signal Handler(相當於Qt C++發送信號給QML端,QML端的Signal Handler進行處理)。
3. 在Qt C++端創建QML對象,既然對象都有了。那你想怎麼樣它就怎麼樣它呗。(沒用過,看起來也不太實用,不過介紹介紹,有用過的同學留言哈)。
好,我們開始吧~
別急,讓我們先來看看,一些東西,如果您都知道,可以跳過此節。
QML API有三個主要成員——QDeclarativeEngine,QDeclarativeComponent和QDeclarativeContext。
QDeclarativeEngine提供了QML的運行環境。
QDeclarativeComponent封裝了QML Documents。
QDeclarativeContext允許程序使用QML組件顯示數據。
QML包含一個非常好用的API——QDeclarativeView。通過它,應用程序可以很方便的把QML組件嵌入到QGraphicsView中。QDeclarativeView主要用於在應用程序開發過程中進行快速原型開發。
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QString>
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QString myString READ myString WRITE setmyString NOTIFY myStringChanged)
public:
explicit MyClass(QObject *parent = 0);
Q_INVOKABLE QString getMyString();
signals:
void myStringChanged();
public slots:
void setmyString(QString aString);
QString myString();
private:
QString m_string;
};
#endif // MYCLASS_H
若你想數據元素中的方法可以被QML直接調用有2種方法:
1. 在函數申明前添加 Q_INVOKABLE 宏。
2. 申明成public slots。
QML可以直接訪問改數據元素的屬性,該屬性由QPROPERTY所申明。
具體實現請參考,示例代碼。
//main.cpp
MyClass myObj;
QDeclarativeEngine *engine=viewer.engine();
QDeclarativeContext *context=engine->rootContext();
context->setContextProperty("myObjectExposeByCXProperty", &myObj);
qml中可以直接使用myObjectExposeByCxProperty對象。
//mainpage.qml
...
Button{
...
id:btn1
...
text: qsTr("PROPERTY")
//此處調用myString為MyClass的QPROPERTY的屬性不是方法,所以沒有括號。
onClicked: label.text=myObjectExposeByCXProperty.myString;
}
...
另外一種方式是注冊類型
//main.cpp
qmlRegisterType<MyClass>("RegisterMyType", 1, 0, "MyClassType");
QML中這樣使用
//mainpage.qml
...
import RegisterMyType 1.0
Button{
id:btn2
...
text: qsTr("INOVKABLE")
//此處調用的時INVOKABLE的方法,不是屬性,所以有括號。
onClicked: label.text=myclassExposeByRegType.getMyString();
}
//創建對象,由於QML是解釋執行的,所以放後面也沒什麼關系。
MyClassType
{
id:myclassExposeByRegType
}
步驟:
1. 導入import。
2. 創建對象。
3. id直接使用。
還是使用上面的那例子,在qml中點擊按鈕控件,改變其中對象的字符串,這時候在Qt C++中發送一個signal信號給qml端,qml端接收到使用signal handler響應,改變label2的值。具體代碼如下。
qml中修改string的值。
//mainpage.qml
Button{
id:btn3
text: qsTr("emit stringchanged signal")
onClicked: myObjectExposeByCXProperty.myString="xxxxx";
}
Qt C++觸發信號
//myclass.cpp
void MyClass::setmyString(QString aString)
{
if(aString==m_string)
{
return;
}
m_string=aString;
emit myStringChanged();
}
連接signal handler響應
//mainpage.qml
Connections
{
target: myObjectExposeByCXProperty
onMyStringChanged:label2.text="Signal handler received"
}
有參數形式的:
基本思路,把你的Qt C++中的對象暴露給QML端,然後利用signals-slots 進行連接,並傳遞消息。具體步驟如下
1 創建自己的對象,如果你的對象是要顯示在QML端,可以繼承QDeclarativeItem,如果只是一個控制類,而不需要顯示在QML端,只需要繼承QObject。這裡用到數據綁定請參考Using QML Bindings in C++ Applications
#include<QObject>
class NetConnectController : public QObject
{
Q_OBJECT
Q_PROPERTY(int status READ status WRITE setStatus NOTIFY statusChanged)
public:
explicit NetConnectController(QObject *parent = 0);
void Ready()
{
emit statusChanged( m_status);
}
signals:
void statusChanged(int aStatus);
private:
int status() const;
void setStatus(int aStatus);
private :
//表示網絡不同的狀態
int m_status;
};
2 暴露你的對象給QML
.....
NetConnectController netController
QDeclarativeEngine * engine = viewer.engine();
(engine->rootContext())->setContextProperty("NetController",&netController);
.....
3在QML中連接Signal-slot
......
Connections
{
target: NetController
onStatusChanged:changeStatus(aStatus)//Call JS Function
}
......
注意:上面的onStatusChanged 命名格式 “on”+"Qt C++中的signal名字"。在QML端可以直接使用Qt C++端的參數。例如上面的"aStatus"。
同樣的QML的函數也可以被Qt C++端調用。
所有的QML函數都通過meta-object system暴露Qt C++端,在Qt C++端可以使用QMetaObject::invokeMethod()方法直接調用。下面就是這樣的一個例子。
// MyItem.qml
import QtQuick 1.0
Item {
function myQmlFunction(msg) {
console.log("Got message:", msg)
return "some return value"
}
}
// main.cpp
QDeclarativeEngine engine;
QDeclarativeComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;
注意:QMetaObject::invokeMethod()方法中的參數Q_RETURN_ARG()和Q_ARG()都被定義為QVariant類型,此類型是QML函數的的參數和返回值的通用數據類型。
更多例程可以在SDK的安裝目錄中:\QtSDK\Examples\4.7\declarative\tutorials\extending 看到。