QtQuick 可以使用內置的 JavaScript 引擎加載相應的 JS 代碼,使用起來特別方便。
在 Qt 中使用 C++ 開發底層,QtQuick 用來加載、處理圖像,然后使用 Qt 提供的接口保證兩者能夠正常通信即可。
1. 首先用Qt Creator新建項目,選擇Qt Quick Controls 2 Application,命名項目…
2. 在資源文件qml.qrc中添加一個qml文件,命名…
3. 在qml文件中輸入相應的元素(Item,Rectanger,Image,Canvas等等)。
1 import QtQuick 2.0 2 import QtQuick.Window 2.2 3 4 Window { 5 width: 800 6 height: 600 7 visible: true 8 title: "Test window" 9 }
這里僅用了一個 Window 元素,加載后只顯示一個空白的窗體。
4. 在main函數中加載qml引擎需要用到QQmlApplicationEngine類,通過該類加載qml文件。如下:
1 int main(int argc, char *argv[]) 2 { 3 QGuiApplication app(argc, argv); 4 5 QQmlApplicationEngine engine; 6 engine.load(QUrl(QStringLiteral("qrc:/Test.qml"))); 7 8 return app.exec(); 9 }
其中,engine 對象的 load() 方法,需要一個QUrl對象提供qml文件的url路徑,這里加載了一個qml文件,即“Test.qml”文件。
運行之后得到空白的窗體。如果想要顯示不同的內容,需要在qml文件中添加相應的元素或自己編寫控件再添加。
用 QQmlApplicationEngine 加載的 qml 文件可以使用 QML 的 Window 控件。
但是在c++ 的類方法中無法直接使用 QQmlApplicationEngine 類,若使用該類加載 qml 文件,會導致在觸發顯示窗口事件時,窗口顯示一下立即消失,但是程序依然在運行,因此就無法對qml窗口進行操作。
1 void Data::view() { 2 QQmlApplicationEngine engine; 3 engine.load(QUrl(QStringLiteral("qrc:/Test.qml"))); 4 }
在Data類的view()方法中使用 QQmlApplicationEngine load() 方法無法正常顯示窗口。
那么,如何在方法中調用加載 qml 文件呢?
要在 c++ 文件中顯示qml文件的內容,Qt 提供了 QQuickView 類(QtQuick1.0則是使用 QDeclaritiveView 類,但是該類在加載 qml 文件時,響應緩慢)使用 QQuickView 即可加載 qml 並顯示內容。
1 void Data::view() { 2 QQuickView *compassview = new QQuickView; 3 compassview->setSource(QUrl(QStringLiteral("qrc:/Compass.qml"))); 4 // compassview->rootContext()->setContextProperty("dataRadius", this); 5 QQmlContext *context = compassview->rootContext(); 6 context->setContextProperty("dataSource", this); 7 // 設置窗口圖標 8 QIcon icon = QIcon(QStringLiteral(":/img/compass.ico")); 9 compassview->setIcon(icon); 10 // compassview->set 11 // 設置窗口縮放時,根對象也會隨之縮放 12 compassview->setResizeMode(QQuickView::SizeRootObjectToView); 13 compassview->setTitle("Compass heading pitch & roll"); 14 compassview->show(); 15 16 }
compassview 指向一個 QQuickView 對象,setSource() 方法指定該 QQuickView 對象所要加載的qml文件。
而 compassview->rootContext() 則是獲取對象的根元素上下文,然后用 context 對象的 setContextProperty(const QString *, const QVariant*) 方法設定上下文屬性,即可通過 QVariant 指針從 C++ 向 QML 傳遞數據。
然而如果qml文件是以 Window 作為根元素的話,QQuickView加載時會出現一個警告,因為QQuickView繼承自QQuickWindow(又繼承自QWindow),它本身就是一個窗口類,如果再用 QML 的 Window 控件作為根元素,自然會出現警告,可以忽略掉該警告,也可以將 Window 改成 Item (但要注意,Window 的有些屬性在 Item 中不存在),這樣就不會出現警告了。
然后在 qml 文件中通過設定一個定時器 Timer,可以定時從 c++ 中獲取數據。
1 /* 2 * 設置一個定時器,每隔 500ms 就從數據源中讀取數據,修正圖像 3 */ 4 Timer { 5 id: updateTimer 6 interval: 500 7 running: true 8 repeat: true 9 10 onTriggered: { 11 // console.log("Timer is triggered! ") 12 // var data = DataSource.getData(); 13 var data = dataSource.getRadius() 14 15 data = [0, 0, 0] 16 // h_refresh(data[0]) 17 refresh(data[0], data[1], data[2]) 18 } 19 }
qml中 dataSource 需要與上面的 setContextProperty(“dataSource”, this) 語句中的 dataSource 同名(這樣就可以直接調用相關對象的方法,比如 getRadius() 方法),否則 qml 將無法獲取數據。
C++ 中設置 QQuickView 的窗口圖標、標題等等與 QWindow 類似。
compassview->setResizeMode(QQuickView::SizeRootObjectToView) 設置了根對象大小隨窗口大小改變而改變。這樣就能動態縮放qml內容。
--------------------------------------------------------------------------------
另外需要注意的是,如果先用 Qt 新建了一個 Qt 應用,想要再添加 qml 文件並運行,需要修改項目的 .pro 文件,添加以下內容:
QT += qml quick
這樣,在編譯時才不會出錯。
====================================================
另外,附上完整的代碼
https://github.com/GitFuture/Compass