在Qt界面開發時,用信號槽能夠很容易實現各個窗口控件之間的交互,qml也是能夠的,qml和C++能夠相互調用,能夠在qml代碼中調用C++的類對象,也能夠用C++類來獲取qml的控件對象,下面分別介紹這兩這種用法,須要源碼的能夠翻到最後直接下載。html
Qt 提供了兩種在 QML 環境中使用 C++對象的方式∶git
方式1:在C+中實現一個類,註冊爲 QML 環境的一個類型,在 QML 環境中使用該類型建立對象。app
方式2:在 C++中構造一個對象,將這個對象設置爲 QML 的上下文屬性,在QML 環境中直接使用該屬性。ide
無論哪一種方式,對要導出的 C++類都有要求,不是一個類的全部方法、變量均可以在 QML 語境中使用,定義能夠導出的 C++類 前提條件 要想將一個類或對象導出到 QML 中,下列的前提條件必須知足∶函數
(1)從 QObject 或 QObject 的派生類繼承,並使用Q_OBJECT宏,這和使用信號與槽的前提條件同樣的,這兩個條件是爲了讓一個類可以進入Qt強大的元對象系統(meta-object system)中,只有使用元對象系統,一個類的某些方法或屬性纔可能經過字符串形式的名字來調用,才能夠在 QML 中被訪問。ui
(2)成員函數想在qml中被調用,則須要在聲明前加上Q_INVOKABLEurl
(3)槽函數能夠用類對象在qml代碼中直接調用指針
(4)C++的成員屬性能夠用Q_PROPERTY宏設置code
(5)枚舉體須要用Q_ENUMS導出htm
下面介紹方式1, 例以下面這個類
#ifndef TESTBOX_H #define TESTBOX_H #include <QObject> class TestBox : public QObject { Q_OBJECT Q_ENUMS(ColorType) Q_PROPERTY(int mValue READ getValue WRITE setValue) public: explicit TestBox(QObject *parent = nullptr); enum ColorType { Red, Green, Blue }; // 成員函數想在qml中被調用,則須要在聲明前加上Q_INVOKABLE Q_INVOKABLE int fun1(); int getValue() { return m_value; } Q_INVOKABLE void setValue(int value) { m_value = value; } signals: void sig_Value(); public slots: void on_Get(); private: int m_value = 0; }; #endif // TESTBOX_H
類定義好後,在main.cpp中註冊
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "testbox.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); qmlRegisterType<TestBox>("cpp.qt.TestBox", 1, 0, "TestBox"); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
調用qmlRegisterType註冊類TestBox,版本是1.0, 這個版本號能夠本身定義。
最後在qml代碼中調用
import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.5 import cpp.qt.TestBox 1.0 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") TestBox{ id:tb mValue:123 //能夠在這裏給對象賦值 } Button{ id:btn1 text:"getValue" anchors.left: parent.left anchors.leftMargin: 40 anchors.top: parent.top anchors.topMargin: 60 onClicked: { tb.on_Get() //調用槽函數 } } Button{ id:btn2 text:"setValue" anchors.left: btn1.left anchors.top: btn1.bottom anchors.topMargin: 20 onClicked: { tb.setValue(3456) } } Button{ id:btn3 text:"getenum" anchors.left: btn2.left anchors.top: btn2.bottom anchors.topMargin: 10 onClicked: { valueTextFeild.text = TestBox.Blue //調用枚舉 } } Button{ id:btn4 text:"invoke fun" anchors.left: btn3.left anchors.top: btn3.bottom anchors.topMargin: 10 onClicked: { valueTextFeild.text = tb.fun1() //調用普通成員函數 } } TextField { id:valueTextFeild anchors.left: btn1.right anchors.leftMargin: 15 anchors.top: btn1.top } //連接信號槽 Connections{ target: tb onSig_Value:{ valueTextFeild.text = tb.mValue //獲取成員屬性值 } } }
運行界面以下:
方式2:
在main.cpp中直接建立C++類對象,例以下面的代碼,
engine.rootContext()->setContextProperty("tb", new TestBox);
new對象 tb, 而後在qml中就能夠直接使用tb了。
代碼以下:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "testbox.h" #include <QQmlContext> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); //qmlRegisterType<TestBox>("cpp.qt.TestBox", 1, 0, "TestBox"); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("tb", new TestBox); const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
這種方式有弊端,枚舉值如法直接在qml中得到,能夠用數字代替。
在C++代碼中獲取qml控件時,須要用到objectName
Text{ objectName: "textLabel" text:"Hello World" anchors.centerIn: parent font.pixelSize: 26 } Button{ objectName: "quitBtn" anchors.right: parent.right anchors.rightMargin: 10 anchors.bottom: parent.bottom anchors.bottomMargin: 10 text:qsTr("退出") }
上面的控件在聲明時,都設置了屬性objectName, qt程序在初始化時有個對象樹,在對象樹中根據objectName調用findChild能夠獲取到控件對象指針
//C++獲取qml的控件 QObject* pQuitBtn = pRoot->findChild<QObject*>("quitBtn"); if(pQuitBtn) { QObject::connect(pQuitBtn, SIGNAL(clicked()), &app, SLOT(quit())); } QObject *pText = pRoot->findChild<QObject*>("textLabel"); if(pText) { bool bRet = QMetaObject::invokeMethod(pText, "setText", Q_ARG(QString, "AAAA")); qDebug() << "bRet = " << bRet; //調用失敗,沒有該方法 pText->setProperty("color", QColor::fromRgb(255,0,0)); }
以上具體功能,能夠看個人代碼,連接以下:
https://gitee.com/qwerwo/qml_code
3個工程