標籤:qt
在 C++程式中使用 QML
QML API 是分為三個主類——QDeclarativeEngine QdeclarativeComponent 與 QDecl arativeContext。QDeclarativeEngine 提供 QML 啟動並執行環境QdeclarativeComponent 封 裝了 QML Documents 與 QDeclarativeCo
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();
匯出資料 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>images/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: “images/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或者協助文檔究竟是不是我的文件裡 面沒有還是怎麼的
在 C++程式中使用 QML技術經驗