C++與QML交互的項(xiàng)目實(shí)踐
一直對(duì)于QT的理解和使用都停留在主窗口程序和控制臺(tái)程序,雖然QT的新東西QML聽過也接觸過,但是基本上沒梳理過調(diào)用流程。趁著舊項(xiàng)目要使用QML技術(shù),現(xiàn)在就將C++和QML交互進(jìn)行總結(jié)。
在C++和QML中均可以定義信號(hào)和槽,并且均可以完成信號(hào)和槽的綁定
一. QML中使用C++業(yè)務(wù)類
基本流程如下:
1.將C++注冊(cè)進(jìn)入QML引擎,C++類型在qml中當(dāng)成一個(gè)子組件使用
2.在qml中完成信號(hào)與槽的綁定
測(cè)試代碼:
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)
}
}
}
//加載子頁(yè)面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è)務(wù)類函數(shù)和qml中的方法,例如 qrcode.qml,其中target:bussiness代表上面的id: bussiness,這樣main.qml中包含qrcode.qml,實(shí)現(xiàn)了qml之間的調(diào)用,以及多個(gè)qml和C++之間的調(diào)用。
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("請(qǐng)掃碼")
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ā)射信號(hào)調(diào)用qml中方法,對(duì)應(yīng)方法名為on+大寫字母開頭函數(shù)
emit accountQRCodeGenerated(); emit accountScannedSuccess(); emit accountLoginSuccess();
2.C++業(yè)務(wù)類定義和實(shí)現(xiàn)
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_Hcbusiness.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.主調(diào)函數(shù)
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "cbusiness.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
//qmlRegisterType注冊(cè)C++類型至QML
//arg1:import時(shí)模塊名
//arg2:主版本號(hào)
//arg3:次版本號(hào)
//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.測(cè)試結(jié)果
鼠標(biāo)左鍵點(diǎn)擊:

說明:
信號(hào)和槽的綁定在qml中完成,鼠標(biāo)左鍵按下,首先打印:qml: Qt.LeftButton
bussiness.strValue = "HelloCpp" 觸發(fā) CBusiness::setStrValue(
因?yàn)槿缦拢?/p>
Q_PROPERTY(QString strValue READ getStrValue WRITE setStrValue NOTIFY strValueChanged)
此處= "HelloCpp" 其實(shí)是調(diào)用的setStrValue
)調(diào)用
bussiness.intValue = 2022觸發(fā)CBusiness::setIntValue(
因?yàn)槿缦拢?/p>
Q_PROPERTY(int intValue READ getIntValue WRITE setIntValue NOTIFY intValueChanged)
此處= 2022其實(shí)是調(diào)用的setIntValue
)調(diào)用, 然后調(diào)用emit strValueChanged(strValue);,觸發(fā)qml中 onIntValueChanged調(diào)用,接著addpro++觸發(fā)onAddproChanged調(diào)用
最后調(diào)用CBusiness::sendSignal(),觸發(fā)emit signal1(); emit signal2(m_strValue, m_intValue);信號(hào),調(diào)用qml的槽
function(){console.log('no name qml function')和
function qmlProcess1(str, value)
鼠標(biāo)右鍵點(diǎn)擊:

說明:
鼠標(biāo)右鍵,通過qml信號(hào)調(diào)用到c++的槽函數(shù),并且還傳遞參數(shù)給c++
二.C++使用QML
基本流程如下:
1.在C++中獲得qml對(duì)象指針
2.在C++中完成信號(hào)和槽的綁定
測(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調(diào)用,也可以作為槽函數(shù)
function qmlFun(val_arg) {
console.log("qmlFun execute", val_arg, "return qmlFun_return_result")
return "qmlFun_return_result"
}
//注意槽函數(shù)參數(shù)為var類型
function invokeFromCpp(arg1, arg2) {
console.log("invokeFromCpp execute ", arg1, arg2)
}
}2.C++業(yè)務(wù)類定義和實(shí)現(xiàn)
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_Hcbusiness.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.主調(diào)函數(shù)
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文檔
當(dāng)使用QQuickView時(shí),qml的根不能是Window
*/
QQuickView view(QUrl("qrc:/main.qml"));
view.show();
// 獲取到qml根對(duì)象的指針
QObject *qmlObj = view.rootObject();
/*
修改qml屬性值的方法
QObject::setProperty() QQmlProperty QMetaProperty::write()
*/
// 通過QObject設(shè)置屬性值
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設(shè)置屬性值
qDebug() << "cpp: " << "set qml property width";
item->setWidth(300);
// 通過QQuickItem獲取屬性值
qDebug() << "cpp: " << "get qml property width" << item->width();
// 通過object name訪問加載的QML對(duì)象
// QObject::findChildren()可用于查找具有匹配object name屬性的子項(xiàng)
QObject *qmlRect = qmlObj->findChild<QObject*>("rect");
if(qmlRect)
{
qDebug() << "cpp: " << "get rect color" << qmlRect->property("color");
}
// C++調(diào)用QML方法
QVariant valReturn;
QVariant valArg = "I am cpp";
//Q_RETURN_ARG()和Q_Arg()參數(shù)必須制定為QVariant類型
QMetaObject::invokeMethod(qmlObj, "qmlFun",
Q_RETURN_ARG(QVariant,valReturn),
Q_ARG(QVariant,valArg));
qDebug() << "cpp: " << "QMetaObject::invokeMethod result" << valReturn.toString(); //qml函數(shù)中返回“ok”
CBusiness cppObj;
// cpp和qml信號(hào)與槽關(guān)聯(lián)
// qml信號(hào)綁訂cpp的槽,用QString類型
QObject::connect(qmlObj, SIGNAL(callCpp(QString, QString)), &cppObj, SLOT(invokeFromQml(QString, QString)));
//關(guān)聯(lián)cpp信號(hào)與qml槽
// cpp的信號(hào)綁定qml槽,用QVariant類型
QObject::connect(&cppObj, SIGNAL(callQml(QVariant, QVariant)), qmlObj, SLOT(invokeFromCpp(QVariant, QVariant)));
return app.exec();
}4.測(cè)試結(jié)果

信號(hào)和槽的綁定在c++代碼中完成,在c++中可以修改qml的屬性,獲取qml的屬性,調(diào)用qml的方法,傳遞和獲取參數(shù)均可以
鼠標(biāo)點(diǎn)擊

鼠標(biāo)點(diǎn)擊后,通過qml的信號(hào)callCpp調(diào)用c++的槽函數(shù)invokeFromQml,然后再通過c++的信號(hào)函數(shù)callQml調(diào)用qml的槽函數(shù)invokeFromCpp
三.QVariant中方法canConvert和convert使用總結(jié)
1.canConvert只是報(bào)告QVariant進(jìn)行兩個(gè)類型之間轉(zhuǎn)換的能力,例如QString和Int類型之間的轉(zhuǎn)換,關(guān)注類型
2.convert判斷的是QVariant進(jìn)行兩個(gè)類型的數(shù)據(jù)之間轉(zhuǎn)換的能力,例如“123”和123之間的轉(zhuǎn)換,關(guān)注數(shù)據(jù)
舉例:
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"
到此這篇關(guān)于C++與QML交互的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)C++ QML交互內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Qt6 QML實(shí)現(xiàn)DateTimePicker組件的示例代碼
- Qt?QML實(shí)現(xiàn)無邊框窗口的實(shí)例代碼
- QML與C++交互之創(chuàng)建自定義對(duì)象的實(shí)現(xiàn)
- Qt6+QML實(shí)現(xiàn)Windows屏幕錄制功能
- Qt?Qml實(shí)現(xiàn)毛玻璃效果
- Qt qml實(shí)現(xiàn)動(dòng)態(tài)輪播圖效果
- 基于Qml實(shí)現(xiàn)水印工具
- QML與C++幾種交互方式
- Qt QML使用虛擬鍵盤的示例代碼
- C++與QML進(jìn)行數(shù)據(jù)交互的常見方法總結(jié)
- Qt6 QML Flickable控件詳解
相關(guān)文章
C++?Boost?CircularBuffer算法超詳細(xì)精講
Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱2022-11-11
快來領(lǐng)取!你想要的C++/C語(yǔ)言優(yōu)秀書籍
如何選擇合適的C++/C語(yǔ)言書籍,是不是已經(jīng)眼花繚亂,不知道該選擇哪本好了呢?今天我來為大家分享兩本不可錯(cuò)過的優(yōu)秀書籍2017-09-09
C++中用哈希表封裝myunordered_set和myunordered_map方法詳解
這篇文章主要介紹了C++中用哈希表封裝myunordered_set和myunordered_map方法,封裝通用哈希表底層,快速實(shí)現(xiàn)myunordered_set和myunordered_map,掌握STL無序容器核心設(shè)計(jì),需要的朋友可以參考下2026-05-05
C++利用多態(tài)實(shí)現(xiàn)職工管理系統(tǒng)(項(xiàng)目開發(fā))
這篇文章主要介紹了C++利用多態(tài)實(shí)現(xiàn)職工管理系統(tǒng)(項(xiàng)目開發(fā)),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
C++優(yōu)先級(jí)隊(duì)列的使用指南與模擬實(shí)現(xiàn)
優(yōu)先級(jí)隊(duì)列是一種特殊的隊(duì)列,其中每個(gè)元素都有一個(gè)與之關(guān)聯(lián)的優(yōu)先級(jí),優(yōu)先級(jí)較高的元素會(huì)在隊(duì)列中較早地被處理,而優(yōu)先級(jí)較低的元素會(huì)在后續(xù)處理,本文給大家介紹C++優(yōu)先級(jí)隊(duì)列的使用指南與模擬實(shí)現(xiàn),需要的朋友可以參考下2023-09-09
C語(yǔ)言簡(jiǎn)明講解三目運(yùn)算符和逗號(hào)表達(dá)式的使用
三目運(yùn)算符,又稱條件運(yùn)算符,它是唯一有3個(gè)操作數(shù)的運(yùn)算符,有時(shí)又稱為三元運(yùn)算符。三目運(yùn)算符的結(jié)合性是右結(jié)合的;逗號(hào)表達(dá)式,是c語(yǔ)言中的逗號(hào)運(yùn)算符,優(yōu)先級(jí)別最低,它將兩個(gè)及其以上的式子聯(lián)接起來,從左往右逐個(gè)計(jì)算表達(dá)式,整個(gè)表達(dá)式的值為最后一個(gè)表達(dá)式的值2022-04-04

