当前位置: 首页 > news >正文

QML与C++相互调用函数并获得返回值

这篇博客主要讲解在qml端如何直接调用c++的函数并获得返回值,在c++端如何直接调用qml的函数并获得返回值;

主要以 map 或者 jsonobject、list 或者 jsonarray为主!

其他单个类型,常见的类型,例如QString、int等,就不演示了;一通百通。

目录

1 准备工作

1.1 C++端 

1.2 QML端

2 qml端直接调用c++端函数

3 c++端直接调用qml端函数

3.1 调用qml的qmlFuncObj函数

3.2 调用qml的qmlFuncList函数

4 代码汇总


1 准备工作

1.1 C++端 

定义自定义类型MyObject,并提供QJsonObject funcObj(QString name, int age); 和 QList<QString> funcList(QString name1, QString name2); 两个函数供qml调用;

注意在头文件定义时需要使用 Q_INVOKABLE 去修饰,否则qml端无法调用。

myobject.h

#ifndef MYOBJECT_H
#define MYOBJECT_H#include <QObject>
#include <QDebug>
#include <QJsonObject>
#include <QList>class MyObject : public QObject
{Q_OBJECTpublic:MyObject(QObject *parent = nullptr);  // 构造函数~MyObject();static MyObject *getInstance();/// 返回objQ_INVOKABLE QJsonObject funcObj(QString name, int age);/// 返回listQ_INVOKABLE QList<QString> funcList(QString name1, QString name2);
};#endif // MYOBJECT_H

myobject.cpp

#include "myobject.h"MyObject::MyObject(QObject *parent) : QObject(parent)
{}MyObject::~MyObject()
{
}MyObject *MyObject::getInstance()
{static MyObject *obj = nullptr;if (!obj) {obj = new MyObject;}return obj;
}QJsonObject MyObject::funcObj(QString name, int age)
{QJsonObject obj;obj.insert("name", name);obj.insert("age", age);return obj;
}QList<QString> MyObject::funcList(QString name1, QString name2)
{QList<QString> list;list << name1 << name2 << "第三";return list;
}

这里的QJsonObject也可以是QVariantMap,注意不能是QMap类型,qml无法识别;

这里的QList<QString>也可以是QVector,QQJsonArray等类型;

main.cpp

然后再main函数中将MyObject注册为全局单例对象;

注意代码中已经提前获得了windowObj,即是qml的对象,用于下面调用qml函数使用。

#include <QGuiApplication>
#include <QQmlApplicationEngine>#include <QQmlContext>
#include "myobject.h"#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);QQmlApplicationEngine engine;// 获得全局对象,上下文对象QQmlContext *context = engine.rootContext();// 给qml设置一个全局变量;如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量;另外,定义全局变量会有性能问题context->setContextProperty("SCREEN_WIDTH", 800);// 注册,在需要使用的地方 import MyObj 1.0
//    qmlRegisterType<MyObject>("MyObj", 1, 0, "MyObject");// 注册全局单例对象qmlRegisterSingletonInstance("MyObj", 1, 0, "MyObject", MyObject::getInstance());engine.load(QUrl(QStringLiteral("qrc:/main.qml")));if (engine.rootObjects().isEmpty())return -1;// 在engine加载完成后,就可以获取qml的所有对象了QList<QObject*> list = engine.rootObjects();// list的首个元素就是windowQObject *windowObj = list.first();return app.exec();
}

1.2 QML端

定义两个函数,function qmlSlot(name, age) 和 function qmlFuncObj(name, age) 供C++调用;

// 定义qml函数
function qmlFuncObj(name, age) {let obj = { };obj["name"] = nameobj["age"] = ageobj["sex"] = "man"return obj//return JSON.stringify(obj)  // 返回JSON字符串
}// 定义qml函数
function qmlFuncList(name, age) {let list = [];list.push(name)list.push(age)list.push("666")return list//return JSON.stringify(list)  // 返回JSON字符串
}

2 qml端直接调用c++端函数

注意,调用的c++函数,在定义时,必须使用 Q_INVOKABLE 去修饰,否则在qml这里是无法调用的。

如下:

/// 返回obj
Q_INVOKABLE QJsonObject funcObj(QString name, int age);
/// 返回list
Q_INVOKABLE QList<QString> funcList(QString name1, QString name2);

 然后,就可以在qml端直接调用c++的函数了,使用 let 定义变量接收返回值即可!

Button {width: 100; height: 50objectName: "myButton"onClicked: {// 直接调用c++函数let obj = MyObject.funcObj("小明", 99)console.log("name:", obj["name"], "   age:", obj["age"])let list = MyObject.funcList("第一", "第二");console.log("count:", list.length)// 遍历方式一for (let i = 0; i < list.length; ++i) {console.log("list:", list[i])}// 遍历方式二for (const item of list) {console.log(item);}}
}

通过点击按钮后,即可调用c++函数,并且得到返回值做打印:

3 c++端直接调用qml端函数

在c++中调用qml的函数,需要使用到QMetaObject::invokeMethod函数,其是重载函数;

函数原型:

static inline bool invokeMethod(QObject *obj, const char *member,QGenericReturnArgument ret,QGenericArgument val0 = QGenericArgument(nullptr),QGenericArgument val1 = QGenericArgument(),QGenericArgument val2 = QGenericArgument(),QGenericArgument val3 = QGenericArgument(),QGenericArgument val4 = QGenericArgument(),QGenericArgument val5 = QGenericArgument(),QGenericArgument val6 = QGenericArgument(),QGenericArgument val7 = QGenericArgument(),QGenericArgument val8 = QGenericArgument(),QGenericArgument val9 = QGenericArgument())
{return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3,val4, val5, val6, val7, val8, val9);
}

参数一:qml对象指针;

参数二:调用qml的函数名;

参数三:调用函数的返回值;

剩余参数:调用qml函数的传参参数;

返回值:调用成功返回true,其他返回false。

当然,还有很多函数重载,这里主要介绍有返回值的,其他那些都类似。

注意,定义接收函数返回的类型变量和传参的函数变量使用的类型均是QVaraint类型。有兴趣的可以尝试一下目标类型,看下行不行。

3.1 调用qml的qmlFuncObj函数

// 定义接受的返回值
QVariant res;
// 定义参数
QVariant arg_name = "jtom";
QVariant arg_age = 26;
// 调用qml函数
bool flag = QMetaObject::invokeMethod(windowObj, "qmlFuncObj",Q_RETURN_ARG(QVariant, res),Q_ARG(QVariant, arg_name),Q_ARG(QVariant, arg_age));
qDebug() << "res = " << res;

windowObj 是 qml的对象指针,在准备工作中已经获得!

通过打印res返回查看,得到返回结果是一个QJSValue类型,是一个JavaScript类型。

如果需要获得QJsonObject类型,则需要将res转成QJSValue类型后,再转成QVaraint类型,再转成QJsonObject类型;

如果需要获得QMap类型,则需要将res转成QJSValue类型后,再转成QVaraint类型,再转成QMap类型;

if (flag) {QJSValue jsValue = res.value<QJSValue>();// 方式一,转换为 QJsonObjectQJsonObject jsonObj = jsValue.toVariant().toJsonObject();qDebug() << jsonObj << "  " << jsonObj["name"] << "  " << jsonObj["age"] << "  " << jsonObj["sex"];// 方式二,转换为QMapQMap<QString, QVariant> map = jsValue.toVariant().toMap();qDebug() << map;
}

注意,以上前提是调用qml函数返回的是QJSValue类型;

当然,返回时,也可以直接返回json字符串,那么接收到后就可以直接转成QJsonDocument去处理了。

在qml函数中,将obj转成json字符串后再返回,如下:

function qmlFuncObj(name, age) {let obj = { };obj["name"] = nameobj["age"] = ageobj["sex"] = "man"//return objreturn JSON.stringify(obj)  // 返回JSON字符串
}

然后就可以当作json字符串的方式去处理解析了,如下:

if (flag) {QJsonDocument doc = QJsonDocument::fromJson(res.toString().toUtf8());QJsonObject jsonObj = doc.object();qDebug() << jsonObj << "  " << jsonObj["name"] << "  " << jsonObj["age"] << "  " << jsonObj["sex"];
}

可以看出,转为json字符串返回后,c++接收到的类型不再是QJSValue类型,而是QString类型。

3.2 调用qml的qmlFuncList函数

// 定义接收返回值变量
QVariant res;
// 定义参数
QVariant arg_name = "jtom";
QVariant arg_age = "266";
// 调用qml函数
bool flag = QMetaObject::invokeMethod(windowObj, "qmlFuncList",Q_RETURN_ARG(QVariant, res),Q_ARG(QVariant, arg_name),Q_ARG(QVariant, arg_age));qDebug() << "res = " << res;

可以看出,返回值也是一个QJSValue类型,处理方式与上面类似了。

if (flag) {// 方法1:转换为 QVariantList(推荐)QVariantList list = res.toList();qDebug() << "List:" << list;qDebug() << "Elements:" << list[0] << list[1] << list[2];// 方法2:转换为 QJsonArrayQJsonArray jsonArray = QJsonArray::fromVariantList(res.toList());qDebug() << "JSON Array:" << jsonArray;
}

注意,以上前提是调用qml函数返回的是QJSValue类型;

当然,返回时,也可以直接返回json字符串,那么接收到后就可以直接转成QJsonDocument去处理了。

在qml函数中,将list转成json字符串后再返回,如下:

function qmlFuncList(name, age) {let list = [];list.push(name)list.push(age)list.push("666")//        return list;return JSON.stringify(list)
}

然后就可以当作json字符串的方式去处理解析了,如下:

if (flag) {QJsonDocument doc = QJsonDocument::fromJson(res.toString().toUtf8());QJsonArray jsonArr = doc.array();qDebug() << jsonArr;
}

可以看出,转为json字符串返回后,c++接收到的类型不再是QJSValue类型,而是QString类型。

4 代码汇总

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>#include <QQmlContext>
#include "myobject.h"#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);QQmlApplicationEngine engine;// 获得全局对象,上下文对象QQmlContext *context = engine.rootContext();// 给qml设置一个全局变量;如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量;另外,定义全局变量会有性能问题context->setContextProperty("SCREEN_WIDTH", 800);// 注册,在需要使用的地方 import MyObj 1.0
//    qmlRegisterType<MyObject>("MyObj", 1, 0, "MyObject");qmlRegisterSingletonInstance("MyObj", 1, 0, "MyObject", MyObject::getInstance());engine.load(QUrl(QStringLiteral("qrc:/main.qml")));if (engine.rootObjects().isEmpty())return -1;// 在engine加载完成后,就可以获取qml的所有对象了QList<QObject*> list = engine.rootObjects();// list的首个元素就是windowQObject *windowObj = list.first();{// 定义接受的返回值QVariant res;// 定义参数QVariant arg_name = "jtom";QVariant arg_age = 26;// 调用qml函数bool flag = QMetaObject::invokeMethod(windowObj, "qmlFuncObj",Q_RETURN_ARG(QVariant, res),Q_ARG(QVariant, arg_name),Q_ARG(QVariant, arg_age));qDebug() << "res = " << res;
//        if (flag) {
//            QJSValue jsValue = res.value<QJSValue>();//            // 方式一,转换为 QJsonObject
//            QJsonObject jsonObj = jsValue.toVariant().toJsonObject();
//            qDebug() << jsonObj << "  " << jsonObj["name"] << "  " << jsonObj["age"] << "  " << jsonObj["sex"];//            // 方式二,转换为QMap
//            QMap<QString, QVariant> map = jsValue.toVariant().toMap();
//            qDebug() << map;
//        }if (flag) {QJsonDocument doc = QJsonDocument::fromJson(res.toString().toUtf8());QJsonObject jsonObj = doc.object();qDebug() << jsonObj << "  " << jsonObj["name"] << "  " << jsonObj["age"] << "  " << jsonObj["sex"];}}{// 定义接受的返回值QVariant res;// 定义参数QVariant arg_name = "jtom";QVariant arg_age = "266";// 调用qml函数bool flag = QMetaObject::invokeMethod(windowObj, "qmlFuncList",Q_RETURN_ARG(QVariant, res),Q_ARG(QVariant, arg_name),Q_ARG(QVariant, arg_age));qDebug() << "res = " << res;
//        if (flag) {
//            // 方法1:转换为 QVariantList(推荐)
//            QVariantList list = res.toList();
//            qDebug() << "List:" << list;
//            qDebug() << "Elements:" << list[0] << list[1] << list[2];//            // 方法2:转换为 QJsonArray
//            QJsonArray jsonArray = QJsonArray::fromVariantList(res.toList());
//            qDebug() << "JSON Array:" << jsonArray;
//        }if (flag) {QJsonDocument doc = QJsonDocument::fromJson(res.toString().toUtf8());QJsonArray jsonArr = doc.array();qDebug() << jsonArr;}}return app.exec();
}

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.14import MyObj 1.0    // 导入自定义模块Window {id: rootvisible: truewidth: SCREEN_WIDTHheight: 500title: qsTr("Hello World")color: "white"objectName: "window"// 定义qml端槽函数function qmlSlot(name, age) {console.log("qml:name = ", name, "   age = ", age);}// 定义qml函数function qmlFuncObj(name, age) {let obj = { };obj["name"] = nameobj["age"] = ageobj["sex"] = "man"//return objreturn JSON.stringify(obj)  // 返回JSON字符串}// 定义qml函数function qmlFuncList(name, age) {let list = [];list.push(name)list.push(age)list.push("666")//        return list;return JSON.stringify(list)}Button {width: 100; height: 50objectName: "myButton"onClicked: {let obj = MyObject.funcObj("小明", 99)console.log("obj:", obj, "   name:", obj["name"], "   age:", obj["age"])let list = MyObject.funcList("第一", "第二");console.log("list:", list, "   count:", list.length)//            // 遍历方式一for (let i = 0; i < list.length; ++i) {console.log("list:", list[i])}
//            // 遍历方式二for (const item of list) {console.log(item);}}}
}

qml与c++相互调用函数已经介绍完毕,具体用法看具体项目吧!

http://www.xdnf.cn/news/1107289.html

相关文章:

  • PID控制算法理论学习基础——单级PID控制
  • 多 Agent 强化学习实践指南(一):CTDE PPO 在合作捕食者-猎物游戏中的应用详解
  • GitHub 操作指南:项目协作与自动化工作流实践
  • 【小沐杂货铺】基于Three.JS绘制汽车展示Car(WebGL、vue、react、autoshow、提供全部源代码)
  • 【Elasticsearch】function_score与rescore
  • html-初级标签
  • 【离线数仓项目】——数据模型开发实战
  • S7-200 SMART PLC:硬件、原理及接线特点全解析
  • 别再怕 JSON!5分钟带你轻松搞懂这个程序员的好帮手
  • C#调用Matlab生成的DLL
  • C++ Map 和 Set 详解:从原理到实战应用
  • win10安装Rust Webassembly工具链(wasm-pack)报错。
  • 细谈kotlin中缀表达式
  • RISC-V:开源芯浪潮下的技术突围与职业新赛道 (四) 产业应用全景扫描
  • Vim的magic模式
  • javaEE——synchronized关键字
  • Linux解决vim中文乱码问题
  • Spring AOP 是如何生效的(入口源码级解析)?
  • leetcode:HJ18 识别有效的IP地址和掩码并进行分类统计[华为机考][字符串]
  • 【Datawhale AI夏令营】mcp-server
  • [Python] Flask 多线程绘图时报错“main thread is not in main loop”的解决方案
  • 【unity实战】在Unity实现低耦合可复用的交互系统
  • 14. 请谈一下浏览器的强缓存和协商缓存
  • 基于大模型的鼻咽癌全周期预测及诊疗优化研究报告
  • YOLO家族内战!v5/v8/v10谁才是你的真命天子?(附保姆级选择指南)
  • 推荐系统-数据分割、性能验证
  • 开源 python 应用 开发(五)python opencv之目标检测
  • (LeetCode 面试经典 150 题 ) 209. 长度最小的子数组(双指针)
  • Vue.js:从 Web 到桌面的跨端实践与技术选型指南
  • 华为IPD(集成产品开发)流程是其研发管理的核心体系