在 C++程序中使用 QML
QML API 是分爲三個主類——QDeclarativeEngine QdeclarativeComponent 與 QDecl arativeContext。QDeclarativeEngine 提供 QML 運行的環境QdeclarativeComponent 封 裝了 QML Documents 與 QDeclarativeCohtml
ntext 容許程序導出數據到 QML 組件實例。 QML 還包含了 API 的一個方便 經過 QDeclarativeView 應用程序只須要簡單嵌入 QML 組 件到一個新的 QGraphicsView 就能夠了。這有許多細節將在下面討論。QDeclarativeView 主要是用於快速成型的應用程序裏。 若是你是從新改進使用 QML 的 Qt 應用程序請參閱 整合 QML 到現有的 Qt UI 代碼。 基本用法 每一個應用程序至少需求一個 QDeclarativeEngine。QDeclarativeEngine 容許配置全局設置 應用到全部的 QML 組件實例中 例如 QNetworkAccessManager 是用於網絡通訊以及永久 儲存的路徑。若是應用程序需求在 QML 組件實例間需求不一樣的設置只須要多個 QDeclarati veEngine。 使用 QDeclarativeComponent 類載入 QML Documents。每一個 QDeclarativeComponent 實例呈現單一 QML 文檔。 QDeclarativeComponent 能夠傳遞一個文檔的地址或文檔的原始 文本內容。該文檔的 URL 能夠是本地文件系統的地址或經過 QNetworkAccessManager 支 持的網絡地址。 QML 組件實例經過調用 QDeclarativeComponent::create()模式來建立。在這裏載入一個 Q ML 文檔的示例而且從它這裏建立一個對象。 QDeclarativeEngine *engine = new QDeclarativeEngine(parent); QDeclarativeComponent component(engine, QUrl::fromLocalFile(「main.qml」)); QObject *myObject = component.create();
c++
導出數據 QML 組件是以 QDeclarativeContext 實例化的。context 容許應用程序導出數據到該 QML 組件實例中。 單個 QDeclarativeContext 可用於一應用程序的全部實例對象或針對每一個實例 使用 QDeclarativeContext 能夠建立更爲精確的控制導出數據。若是不傳遞一個 context 給 QDeclarativeComponent::create()模式那麼將使用 QDeclarativeEngine 的 root context。 數據導出經過該 root context 對全部對象實例是有效的。 簡單數據 爲了導出數據到一個 QML 組件實例應用程序設置 Context 屬性而後由 QML 屬性綁定 的名稱與 JavaScrip 訪問。下面的例子顯示經過 QGraphicsView 如何導出一個背景顏色到
QML 文件中 //main.cpp #include <QApplication> #include <QDeclarativeView> #include <QDeclarativeContext>
int main(int argc, char *argv[]) { QApplication app(argc, argv);
QDeclarativeView view; QDeclarativeContext *context = view.rootContext(); context->setContextProperty(「backgroundColor」, QColor(Qt::yellow));
view.setSource(QUrl::fromLocalFile(「main.qml」)); view.show();
return app.exec(); }
//main.qml import Qt 4.7
Rectangle { width: 300 height: 300
color: backgroundColor
Text { anchors.centerIn: parent text: 「Hello Yellow World!」 } } 或者 若是你須要 main.cpp 不須要在 QDeclarativeView 顯示建立的組件 你就須要使用 Q DeclarativeEngine::rootContext()替代建立 QDeclarativeContext 實例。 QDeclarativeEngine engine; QDeclarativeContext *windowContext = new QDeclarativeContext(engine.rootContext ()); windowContext->setContextProperty(「backgroundColor」, QColor(Qt::yellow));
QDeclarativeComponent component(&engine, 「main.qml」); QObject *window = component.create(windowContext);
Context 屬性的操做像 QML 綁定的標準屬性那樣——在這個例子中的 backgroundColor C ontext 屬性改變爲紅色那麼該組件對象實例將自動更新。注意刪除任意 QDeclarativeC
ontext 的構造是建立者的事情。當 window 組件實例撤消時再也不須要 windowContext 時w indowContext 必須被消毀。最簡單的方法是確保它設置 window 做爲 windowContext 的父 級。 QDeclarativeContexts 是樹形結構——除了 root context 每一個 QDeclarativeContexts 都有 一個父級。子級 QDeclarativeContexts 有效的繼承它們父級的 context 屬性。這使應用程序 分隔不一樣數據導出到不一樣的 QML 對象實例有更多自由性。若是 QDeclarativeContext 設置 一 context 屬性一樣它父級也被影響新的 context 屬性是父級的影子。以下例子中ba ckground context 屬性是 Context 1也是 root context 裏 background context 屬性的影 子。
結構化數據 context 屬性一樣可用於輸出結構化與寫數據到 QML 對象。除了 QVariant 支持全部已經存 在的類型外 QObject 派生類型能夠分配給 context 屬性。 QObject context 屬性容許數據 結構化輸出並容許 QML 來設置值。 下例建立 CustomPalette 對象並設置它做爲 palette context 屬性。 class CustomPalette : public QObject { Q_OBJECT Q_PROPERTY(QColor background READ background WRITE setBackground NOTIF Y backgroundChanged) Q_PROPERTY(QColor text READ text WRITE setText NOTIFY textChanged)
public: CustomPalette() : m_background(Qt::white), m_text(Qt::black) {}
QColor background() const { return m_background; } void setBackground(const QColor &c) { if (c != m_background) { m_background = c; emit backgroundChanged(); } }
QColor text() const { return m_text; } void setText(const QColor &c) { if (c != m_text) { m_text = c; emit textChanged(); } }
signals: void textChanged();
void backgroundChanged();
private: QColor m_background; QColor m_text; };
int main(int argc, char *argv[]) { QApplication app(argc, argv);
QDeclarativeView view; view.rootContext()->setContextProperty(「palette」, new CustomPalette);
view.setSource(QUrl::fromLocalFile(「main.qml」)); view.show();
return app.exec(); }
QML 引用 palette 對象以及它的屬性爲了設置背景與文本的顏色這裏是當單擊窗口時 面板的文本顏色將改變成藍色。 import Qt 4.7
Rectangle { width: 240 height: 320 color: palette.background
Text { anchors.centerIn: parent color: palette.text text: 「Click me to change color!」 }
MouseArea { anchors.fill: parent onClicked: { palette.text = 「blue」; } } }
能夠檢測一個 C++屬性值——這種狀況下的 CustomPalette 的文本屬性改變該屬性必須 有相應的 NOTIFY 信息。NOTIFY 信號是屬性值改變時將指定一個信號發射。 實現者應該注意的是 只有值改變時才發射信號 以防止發生死循環。 訪問一個綁定的屬性
沒有 NOTIFY 信號的話將致使 QML 在運行時發出警告信息。 動態結構化數據 若是應用程序對結構化過於動態編譯 QObject 類型那麼對動態結構化數據可在運行時使 用 QDeclarativePropertyMap 類構造。
從 QML 調用 C++ 經過 public slots 輸出模式或 Q_INVOKABLE 標記模式使它能夠調用 QObject 派生出的類 型。 C++模式一樣能夠有參數而且能夠返回值。QML 支持以下類型 ?bool ?unsigned int, int ?float, double, qreal ?QString ?QUrl ?QColor ?QDate,QTime,QDateTime ?QPoint,QPointF ?QSize,QSizeF ?QRect,QRectF ?QVariant 下面例子演示了當 MouseArea 單擊時控制「Stopwatch」對象的開關。 //main.cpp class Stopwatch : public QObject { Q_OBJECT public: Stopwatch();
Q_INVOKABLE bool isRunning() const;
public slots: void start(); void stop();
private: bool m_running; };
int main(int argc, char *argv[]) { QApplication app(argc, argv);
QDeclarativeView view; view.rootContext()->setContextProperty(「stopwatch」, new Stopwatch);
view.setSource(QUrl::fromLocalFile(「main.qml」)); view.show();
return app.exec(); }
//main.qml
import Qt 4.7
Rectangle { width: 300 height: 300
MouseArea { anchors.fill: parent onClicked: { if (stopwatch.isRunning()) stopwatch.stop() else stopwatch.start(); } } }
值得注意的是在這個特殊的例子裏有更好的方法來達到一樣的效果在 main.qml 有」run ning」屬性這將會是一個很是優秀的 QML 代碼 // main.qml import Qt 4.7
Rectangle {
MouseArea { anchors.fill: parent onClicked: stopwatch.running = !stopwatch.running } }
固然它一樣能夠調用 functions declared in QML from C++。
網絡組件 若是 URL 傳遞給 QDeclarativeComponent 是一網絡資源或者 QML 文檔引用一網絡資源 QDeclarativeComponent 要先獲取網絡數據而後才能夠建立對象。在這種狀況下 QDecl arativeComponent 將有 Loading status。直到組件調用 QDeclarativeComponent::create() 以前應用程序將一直等待。 下面的例子顯示如何從一個網絡資源載入 QML 文件。在建立 QDeclarativeComponent 之 後它測試組件是否加載。若是是它鏈接 QDeclarativeComponent::statusChanged()信 號不然直接調用 continueLoading()。這個測試是必要的甚至 URL 均可以是遠程的只 是在這種狀況下要防組件是被緩存的。 MyApplication::MyApplication() { // … component = new QDeclarativeComponent(engine, QUrl(「http://www.example.com/mai n.qml」)); if (component->isLoading()) QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Statu s)), this, SLOT(continueLoading())); else
continueLoading(); }
void MyApplication::continueLoading() { if (component->isError()) { qWarning() << component->errors(); } else { QObject *myObject = component->create(); } }
Qt 資源 QML 的內容可使用 qrcURL 方案從 Qt 資源系統載入。例如 [project/example.qrc] <!DOCTYPE RCC> <RCC version=」1.0″>
<qresource prefix=」/」> <file>main.qml</file> <file>p_w_picpaths/background.png</file> </qresource>
</RCC>
[project/project.pro] QT += declarative
SOURCES += main.cpp RESOURCES += example.qrc
[project/main.cpp] int main(int argc, char *argv[]) { QApplication app(argc, argv);
QDeclarativeView view; view.setSource(QUrl(「qrc:/main.qml」)); view.show();
return app.exec(); } [project/main.qml] import Qt 4.7
Image { source: 「p_w_picpaths/background.png」 }
請注意資源系統是不能從 QML 直接訪問的。若是主 QML 文件被加載做爲資源全部的 文件指定在 QML 中作爲相對路徑從資源系統載入。 在 QML 層使用資源系統是徹底透明的。 這也意味着若是主 QML 文件沒有被加載做爲資源那麼從 QML 不能訪問資源系統。
1.這裏主要是介紹如何在 c++中調用 QML 中的函數和設置 QML 中的屬性的問題 2.具體代碼
// UICtest.qml import Qt 4.7 Rectangle { id: mainWidget; width: 640 height: 480 function callbyc(v) { mainWidget.color = v; return "finish"; } Rectangle{ id: secondRect; x: 100; y: 20; width: 400; height: 300; Rectangle{ x: 10; y: 20; width: 30; height: 40; color: "#FF035721" Text { objectName: "NeedFindObj"; anchors.fill: parent;
text: ""; } } } }
// main.cpp #include <QtGui/QApplication> #include <QtDeclarative/QDeclarativeView> #include <QtDeclarative/QDeclarativeEngine> #include <QtDeclarative/QDeclarativeComponent> #include <QtDeclarative/QDeclarativeContext> #include <QtDeclarative/QDeclarativeItem> #include <QMetaObject> int main(int argc, char *argv[]) { QApplication a(argc, argv); QDeclarativeView qmlView; qmlView.setSource(QUrl::fromLocalFile("../UICtest/UICtest.qml")); qmlView.show(); // 獲取根節點就是 QML 中 id 是 mainWidget 的節點 QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(qmlView.rootObject()); item->setProperty("color", QVariant("blue")); // 查找到咱們須要的節點根均 objectname NeedFindObj 來得到並設置他的文本屬性 QDeclarativeItem *item1 = item->findChild<QDeclarativeItem *>("NeedFindObj"); if (item1) { item1->setProperty("text", QVariant("OK")); } // 調用 QML 中的函數, 分別是 函數所在的對象 函數名返回值 參數 QVariant returnVar; QVariant arg1 = "blue"; QMetaObject::invokeMethod(item, "callbyc", Q_RETURN_ARG(QVariant, returnVar),Q_ARG(QVariant, arg1)); qDebug(" %s",returnVar.toString().toLocal8Bit().data()); return a.exec(); }
說明
這裏的根節點是 id 爲 mainWidget 的矩形元素那麼在 C++中獲取根節點後就能夠直接的設 置他的屬性了。其餘屬性也能夠一樣,調用指定節點內的函數是經過 QMetaObject 中的 invokeMethod 來進行調用的。 最後全部關於 QML 和 c++交互部分就基本寫完若是想要更多的東西或者一些其餘方法強 烈看看 http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html或者幫助文檔到底是不是個人文檔裏 面沒有仍是怎麼的緩存