当前位置: 首页 > 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.lryc.cn/news/585914.html

相关文章:

  • 浅谈 Pydantic v2 的 RootModel 与联合类型——构建多请求结构的统一入口模型
  • Linux中的git命令
  • Kimi K2万亿参数开源模型原理介绍
  • 猿人学js逆向比赛第一届第二十题
  • Linux进程的生命周期:状态定义、转换与特殊场景
  • 杭州乐湾科技有限公司的背景、产品体系与技术能力的全方位深度分析
  • linux_线程概念
  • 车载操作系统 --- Linux实时化与硬实时RTOS综述
  • windows电脑远程win系统服务器上的wsl2
  • 部署Harbor私有仓库
  • 服务器怎么跑Python项目?
  • vite如何生成gzip,并在服务器上如何设置开启
  • 自动化证书续签工具针对VPS服务器HTTPS服务的维护实践
  • Python技巧记录
  • 浅谈npm,cnpm,pnpm,npx,nvm,yarn之间的区别
  • 【云端深度学习训练与部署平台】AutoDL连接VSCode运行深度学习项目的全流程
  • Go语言中的Options模式
  • Mac M芯片安装RocketMQ服务
  • tp8.0\jwt接口安全验证
  • 深入解析 LinkedList
  • 在 Android 库模块(AAR)中,BuildConfig 默认不会自动生成 VERSION_CODE 和 VERSION_NAME 字段
  • 手机识别数据集,2628张原始图片,支持yolo,coco json,pasical voc xml等格式的标注
  • 搭建云手机教程
  • 深大计算机游戏开发实验三
  • Apache HTTP Server 从安装到配置
  • 实习内容总结
  • javaEE——synchronized关键字
  • docker 443错误 lookup docker.mirrors.ustc.edu.cn: no such host
  • Vue Vue-route (5)
  • 【C#】GraphicsPath的用法