C++與QML交互的項目實踐
一直對于QT的理解和使用都停留在主窗口程序和控制臺程序,雖然QT的新東西QML聽過也接觸過,但是基本上沒梳理過調用流程。趁著舊項目要使用QML技術,現在就將C++和QML交互進行總結。
在C++和QML中均可以定義信號和槽,并且均可以完成信號和槽的綁定
一. QML中使用C++業(yè)務類
基本流程如下:
1.將C++注冊進入QML引擎,C++類型在qml中當成一個子組件使用
2.在qml中完成信號與槽的綁定
測試代碼:
1.QML定義
main.qml
import QtQuick 2.7 import QtQuick.Window 2.2 import WorkClass 1.0 Window { id: root visible: true width: 640 height: 480 title: qsTr("Hello World") signal qmlSignal1 signal qmlSignal2(string strValue, int iValue) MainForm { anchors.fill: parent mouseArea.onClicked: { Qt.quit(); } } MouseArea{ anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { if(mouse.button === Qt.LeftButton){ console.log(' Qt.LeftButton') bussiness.strValue = "HelloCpp" bussiness.intValue = 2022 bussiness.sendSignal() }else{ console.log(' Qt.RightButton') root.qmlSignal1() root.qmlSignal2('hesy', 2000) } } } //加載子頁面qrcode.qml //Loader { // id:accountQRCode // source:"qrcode.qml" // x:(root.width - root.height / 3) / 2 // y:root.height / 3 // visible: true //} CBusiness{ id: bussiness property int addpro: 0 onIntValueChanged: { console.log('qml onIntValueChanged', "begin change addpro ", addpro) addpro++ console.log('qml onIntValueChanged', addpro) } onAddproChanged: { console.log('qml onAddFun', addpro) } } Component.onCompleted: { bussiness.onSignal1.connect(function(){console.log('no name qml function')}) bussiness.onSignal2.connect(qmlProcess1) root.qmlSignal1.connect(bussiness.slot1) root.qmlSignal2.connect(bussiness.slot2) console.log('Component.onCompleted') } function qmlProcess1(str, value){ console.log('qmlProcess1', str, value) } }
備注:
另外在qml中也可以使用Connections綁定C++業(yè)務類函數和qml中的方法,例如 qrcode.qml,其中target:bussiness代表上面的id: bussiness,這樣main.qml中包含qrcode.qml,實現了qml之間的調用,以及多個qml和C++之間的調用。
import QtQuick 2.0 Item { Image { id: qrcode sourceSize.width: parent.width sourceSize.height: parent.height source: "" } Text { id: tips x: parent.x y: parent.y text: qsTr("請掃碼") font.pixelSize: 24 visible: false } Connections { target:bussiness onAccountQRCodeGenerated: { console.log("onAccountQRCodeGenerated invoke !"); qrcode.source = "image://qrcode/account" } onAccountScannedSuccess: { console.log("onAccountScannedSuccess invoke!"); qrcode.visible = false tips.visible = true } onAccountLoginSuccess: { console.log("onAccountLoginSuccess invoke !"); tips.text = qsTr("登錄成功, 歡迎!") } } }
C++中通過發(fā)射信號調用qml中方法,對應方法名為on+大寫字母開頭函數
emit accountQRCodeGenerated(); emit accountScannedSuccess(); emit accountLoginSuccess();
2.C++業(yè)務類定義和實現
cbusiness.h
#ifndef CBUSINESS_H #define CBUSINESS_H #include <QObject> class CBusiness : public QObject { Q_OBJECT Q_PROPERTY(QString strValue READ getStrValue WRITE setStrValue NOTIFY strValueChanged) Q_PROPERTY(int intValue READ getIntValue WRITE setIntValue NOTIFY intValueChanged) public: explicit CBusiness(QObject *parent = 0); Q_INVOKABLE void sendSignal(); void setStrValue(QString strValue); QString getStrValue() const; void setIntValue(int intValue); int getIntValue() const; signals: void signal1(); void signal2(QString strValue, int intValue); void strValueChanged(QString strValue); void intValueChanged(int intValue); public slots: void slot1(); void slot2(QString strValue, int intValue); private: //類的屬性 QString m_strValue; int m_intValue; }; #endif // CBUSINESS_H
cbusiness.cpp
#include "cbusiness.h" #include <QDebug> CBusiness::CBusiness(QObject *parent) : QObject(parent), m_strValue(""), m_intValue(0) { } void CBusiness::sendSignal() { qDebug() << "CBusiness::" << __FUNCTION__; emit signal1(); emit signal2(m_strValue, m_intValue); } void CBusiness::setStrValue(QString strValue) { qDebug() << "CBusiness::" << __FUNCTION__ << strValue; m_strValue = strValue; emit strValueChanged(strValue); qDebug()<< "CBusiness::" << "emit strValueChanged" << endl; } QString CBusiness::getStrValue() const { qDebug() << "CBusiness::" << __FUNCTION__; return m_strValue; } void CBusiness::setIntValue(int intValue) { qDebug() << "CBusiness::" << __FUNCTION__; m_intValue = intValue; emit intValueChanged(intValue); qDebug()<< "CBusiness::" << "emit intValueChanged"; } int CBusiness::getIntValue() const { qDebug() << "CBusiness::" << __FUNCTION__; return m_intValue; } void CBusiness::slot1() { qDebug() << "CBusiness::" << __FUNCTION__; } void CBusiness::slot2(QString strValue, int intValue) { qDebug() << "CBusiness::" << __FUNCTION__; qDebug() << "CBusiness:: " << strValue << " " << intValue; }
3.主調函數
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "cbusiness.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); //qmlRegisterType注冊C++類型至QML //arg1:import時模塊名 //arg2:主版本號 //arg3:次版本號 //arg4:QML類型名 qmlRegisterType<CBusiness>("WorkClass", 1, 0, "CBusiness"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
4.測試結果
鼠標左鍵點擊:
說明:
信號和槽的綁定在qml中完成,鼠標左鍵按下,首先打?。簈ml: Qt.LeftButton
bussiness.strValue = "HelloCpp" 觸發(fā) CBusiness::setStrValue(
因為如下:
Q_PROPERTY(QString strValue READ getStrValue WRITE setStrValue NOTIFY strValueChanged)
此處= "HelloCpp" 其實是調用的setStrValue
)調用
bussiness.intValue = 2022觸發(fā)CBusiness::setIntValue(
因為如下:
Q_PROPERTY(int intValue READ getIntValue WRITE setIntValue NOTIFY intValueChanged)
此處= 2022其實是調用的setIntValue
)調用, 然后調用emit strValueChanged(strValue);,觸發(fā)qml中 onIntValueChanged調用,接著addpro++觸發(fā)onAddproChanged調用
最后調用CBusiness::sendSignal(),觸發(fā)emit signal1(); emit signal2(m_strValue, m_intValue);信號,調用qml的槽
function(){console.log('no name qml function')
和
function qmlProcess1(str, value)
鼠標右鍵點擊:
說明:
鼠標右鍵,通過qml信號調用到c++的槽函數,并且還傳遞參數給c++
二.C++使用QML
基本流程如下:
1.在C++中獲得qml對象指針
2.在C++中完成信號和槽的綁定
測試代碼:
1.QML定義
main.qml
import QtQuick 2.7 import QtQuick.Window 2.2 Item { id: root visible: true width: 640 height: 480 //title: qsTr("Hello World") property string msg: "I am QML Item" signal callCpp(string arg1, string arg2) MainForm { anchors.fill: parent mouseArea.onClicked: { Qt.quit(); } } Rectangle { anchors.fill: parent color: "blue" objectName: "rect" } MouseArea { anchors.fill: parent onClicked: { console.log("onClicked, callCpp") root.callCpp(root.msg, "notify cpp") } } onHeightChanged: { console.log("onHeightChanged execute") } onWidthChanged: { console.log("onWidthChanged execute") } //QML中的方法可以被cpp調用,也可以作為槽函數 function qmlFun(val_arg) { console.log("qmlFun execute", val_arg, "return qmlFun_return_result") return "qmlFun_return_result" } //注意槽函數參數為var類型 function invokeFromCpp(arg1, arg2) { console.log("invokeFromCpp execute ", arg1, arg2) } }
2.C++業(yè)務類定義和實現
cbusiness.h
#ifndef CBUSINESS_H #define CBUSINESS_H #include <QObject> class CBusiness : public QObject { Q_OBJECT public: explicit CBusiness(QObject *parent = 0); signals: void callQml(const QVariant &arg1,const QVariant &arg2); public slots: void invokeFromQml(const QString &arg1,const QString &arg2); }; #endif // CBUSINESS_H
cbusiness.cpp
#include "cbusiness.h" #include <QDebug> CBusiness::CBusiness(QObject *parent) : QObject(parent) { } void CBusiness::invokeFromQml(const QString &arg1,const QString &arg2) { qDebug() << "CBusiness::" << __FUNCTION__ << arg1 << arg2; qDebug() << "CBusiness::" << __FUNCTION__ << " emit callQml"; emit callQml("I am cpp", "notify qml"); }
3.主調函數
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlProperty> #include <QQuickView> #include <QQuickItem> #include <QMetaObject> #include <QDebug> #include "cbusiness.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); /* 可以用QQmlComponent\QQuickView\QQuickWidget的C++代碼加載QML文檔 當使用QQuickView時,qml的根不能是Window */ QQuickView view(QUrl("qrc:/main.qml")); view.show(); // 獲取到qml根對象的指針 QObject *qmlObj = view.rootObject(); /* 修改qml屬性值的方法 QObject::setProperty() QQmlProperty QMetaProperty::write() */ // 通過QObject設置屬性值 qDebug() << "cpp: " << "set qml property height"; QQmlProperty(qmlObj, "height").write(500); //qmlObj->setProperty("height",500); // 通過QObject獲取屬性值 qDebug() << "cpp: " << "get qml property height" << qmlObj->property("height").toDouble(); // C++訪問qml的其它屬性 qDebug() << "cpp: " << "get qml property msg" << qmlObj->property("msg").toString(); // 獲取QQuickItem QQuickItem *item = qobject_cast<QQuickItem*>(qmlObj); // 通過QQuickItem設置屬性值 qDebug() << "cpp: " << "set qml property width"; item->setWidth(300); // 通過QQuickItem獲取屬性值 qDebug() << "cpp: " << "get qml property width" << item->width(); // 通過object name訪問加載的QML對象 // QObject::findChildren()可用于查找具有匹配object name屬性的子項 QObject *qmlRect = qmlObj->findChild<QObject*>("rect"); if(qmlRect) { qDebug() << "cpp: " << "get rect color" << qmlRect->property("color"); } // C++調用QML方法 QVariant valReturn; QVariant valArg = "I am cpp"; //Q_RETURN_ARG()和Q_Arg()參數必須制定為QVariant類型 QMetaObject::invokeMethod(qmlObj, "qmlFun", Q_RETURN_ARG(QVariant,valReturn), Q_ARG(QVariant,valArg)); qDebug() << "cpp: " << "QMetaObject::invokeMethod result" << valReturn.toString(); //qml函數中返回“ok” CBusiness cppObj; // cpp和qml信號與槽關聯 // qml信號綁訂cpp的槽,用QString類型 QObject::connect(qmlObj, SIGNAL(callCpp(QString, QString)), &cppObj, SLOT(invokeFromQml(QString, QString))); //關聯cpp信號與qml槽 // cpp的信號綁定qml槽,用QVariant類型 QObject::connect(&cppObj, SIGNAL(callQml(QVariant, QVariant)), qmlObj, SLOT(invokeFromCpp(QVariant, QVariant))); return app.exec(); }
4.測試結果
信號和槽的綁定在c++代碼中完成,在c++中可以修改qml的屬性,獲取qml的屬性,調用qml的方法,傳遞和獲取參數均可以
鼠標點擊
鼠標點擊后,通過qml的信號callCpp調用c++的槽函數invokeFromQml,然后再通過c++的信號函數callQml調用qml的槽函數invokeFromCpp
三.QVariant中方法canConvert和convert使用總結
1.canConvert只是報告QVariant進行兩個類型之間轉換的能力,例如QString和Int類型之間的轉換,關注類型
2.convert判斷的是QVariant進行兩個類型的數據之間轉換的能力,例如“123”和123之間的轉換,關注數據
舉例:
QString str1 = "Qt5.7.0"; QVariant var1 = str1; qDebug() << var1.canConvert(QVariant::Int); // true qDebug() << var1.convert(QVariant::Int); // false qDebug() << var1.toString(); // "0" var1 = str1; qDebug() << var1.convert(QVariant::String); // true qDebug() << var1.toString(); // "Qt5.7.0" QString str2 = "789"; QVariant var2 = str2; qDebug() << var2.canConvert(QVariant::Int); // true qDebug() << var2.convert(QVariant::Int); // true qDebug() << var2.toString(); // "789"
到此這篇關于C++與QML交互的項目實踐的文章就介紹到這了,更多相關C++ QML交互內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!