【qml】第一次尝试qml与c++交互

news2024/11/18 3:37:57

背景:

目的是学习qml,因为看到很多qml的酷炫效果,想试一试。

看过网上一些代码,qt提供的工具类好几个,看着就晕。只想提炼一下,做个记录。

我先整理了一套自己的想法:所谓交互,还是qt的信号槽。既然是前后端分离设计,就尽量遵循松散耦合的初衷。后端c++用于写逻辑,就像写库一样,考虑好用途和接口,只要调试通过,就不用管了。只需要把qml当做使用者,去调用c++即可。

为了简单,实例化放在c++中,qml中只管调用即可。

因此,做了一个demo试验一下。

demo:

先用qt新建一个空的quick项目。在c++中添加一个具有信号槽的类,然后在qml中尝试调用它。

先做一个类MyClass.h:

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QDebug>

class MyClass : public QObject
{
    Q_OBJECT
public:
    MyClass();

signals:
    void sigFromCpp(QVariant s);

public slots:
    inline void onCpp(QString s)
    {
        qDebug() << "The cpp slot is called:" << __FUNCTION__ << s;
        qDebug() << "The cpp signal is sent.";
        emit sigFromCpp(s);
    }
};

#endif // MYCLASS_H

Myclass.cpp:

#include "myclass.h"

MyClass::MyClass()
{

}

已经尽量简单。

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myclass.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;


    //--------------------------------------------
    /**
     * 这一段是自己添加的。
     * 实测:放在engine加载前面没有报错。
     * 放在engine加载后面,一样能出结果,但是会有报错。
     * 所以,应该放在前面。
     */
    QQmlContext *oContext = engine.rootContext();
    oContext->setContextProperty("g_iWidth", 500);
    oContext->setContextProperty("g_iHeight", 500);

    MyClass obj;
    oContext->setContextProperty("g_obj", &obj);
    //--------------------------------------------



    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();
}

只有中间那一段是自己加的。其中QQmlContext::setContextProperty()函数,就当是在c++中,为qml定义全局变量。我打算用c++的命名习惯来做,所以全局变量一律g_开头,变量名加上类型标识。

所以g_iWidth和g_iHeight表示宽和高,g_obj表示c++对象。

main.qml:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.12

Window {
    id: mainwindow
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    signal qmlSig(string s)

    function qmlSlot(s) {
        console.log("The qml slot is called:", s)

        //这里使用c++指定的全局变量重新设置窗体大小
        mainwindow.setWidth(g_iWidth)
        mainwindow.setHeight(g_iHeight)
    }

    Button {
        id: btnChangeSize
        text: qsTr("Change size")
        onClicked: {
            //qml如果要“发信号”给c++,两种方式:

            //g_obj.onCpp("The button is clicked.")//直接调用了c++的槽函数

            qmlSig("me")//发信号
        }
    }

    onQmlSig: {
        console.log("The qml signal is sent.")
        g_obj.onCpp("The button is clicked.")
    }

    Connections {
        target: g_obj

        /**
         * 亲测:函数的“形参”可以不写,函数体中使用的变量名,和c++信号中的一样。
         * function onSigFromCpp() {
         *     qmlSlot(s)//是和c++里的信号对应的:void sigFromCpp(QVariant s);
         * }
         *
         * 当然,如果指定了形参,形参的名字可以用,直接用信号里那个也行。
         */
        function onSigFromCpp(ss) {
            qmlSlot(ss)//亲测用s也行
        }

        /**
         * 尝试以下写法,也可以的。
         *
         * onSigFromCpp: {
         *     qmlSlot(s + "234")
         * }
         *
         * 但是,亲测几点注意:
         * 1.不能在后面直接跟参数,像这样不行:onSigFromCpp(s): {...}
         * 2.上面参数直接用“s”,是和c++里的信号对应的:void sigFromCpp(QVariant s);
         * 3.只能写在connections里面,因为qml是按代码块对应的。就像:
         *   Button块里面可以直接onClicked,因为clicked信号是button发出的。
         *   Window块里面可以直接onQmlSig,因为qmlSig信号是在Window块定义的。
         */
    }

}

以上代码中,我认为关键的地方都做了注释。本文最后会有总结。

效果:

运行之后显示带一个按钮的默认窗体,点击按钮之后:

qml响应按钮clicked信号,发出自定义信号qmlSig通知c++;

c++槽函数响应,再发出c++信号给qml;

qml槽函数响应。

之所以要兜一圈,仅仅为了测试信号槽的控制方式。

界面如下:

点击按钮之后,窗体改变大小:

同时调试信息输出如下:

qml: The qml signal is sent.

The cpp slot is called: onCpp "The button is clicked."

The cpp signal is sent.

qml: The qml slot is called: The button is clicked.

达到预期。

要点1:

main.cpp中,如果对engine有设置,需要放在load之前。本次demo就是执行setContextProperty那里,应该放在engine.load之前,如果放在后面,亲测运行效果也能出来,但是调试输出是有错误的:

qrc:/main.qml:34:5: QML Connections: Detected function "onSigFromCpp" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.
qrc:/main.qml:35: ReferenceError: g_obj is not defined
qrc:/main.qml:35: ReferenceError: g_obj is not defined
qrc:/main.qml:35: ReferenceError: g_obj is not defined

见名知意不用解释,也许能运行是跟qt内部机制有关,感兴趣可以看源码,但只是使用的话,记住最后load即可。

要点2:

关于MyClass,定义的信号形参类型,现在是QVariant,亲测QString也行。具体以后用到时,一切以运行结果为准。

要点3:

关于main.qml,毕竟它是用来描述ui的,我就姑且认为和QWidget类似,一块一块的区域,就像widget对象树那样。所以如果要定义信号或槽,一定要写在对应的“块”当中。

所谓发qml信号,只需要定义一个信号,然后像函数一样调用即可,没有emit。当然c++里不写emit也行(严谨易读,还是写上)。

qml槽,写在对应块里面时,可以像属性一样直接加冒号,就如:onClicked:{...}既然是“属性”,当然要写在对应的“块”当中。

如果qml槽用于响应含参数的c++信号,两种写法:

要么像函数一样带function关键字,可以带形参,也可以不带形参,不带形参时,函数体中直接使用c++信号中的形参名。

要么像属性一样不带形参,带冒号,因为没有形参,只能使用c++信号中的形参名。

我也不知道为什么,只是今天实测的结果是这样。如果有哪位知道原因或者有更好的建议,请赐教。

本文完。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1371780.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浏览器缓存引发的odoo前端报错

前两天&#xff0c;跑了一个odoo16项目&#xff0c;莫名其妙的前端报错&#xff0c; moment.js 报的错&#xff0c; 这是一个时间库&#xff0c;不是我自己写的代码&#xff0c;我也没做过任何修改&#xff0c;搞不清楚为什么报错。以为是odoo的bug&#xff0c;所以从gitee下载…

K8S存储卷和数据卷

容器内的目录和宿主机的目录进行挂载 容器在系统上的生命周期是短暂的&#xff0c;delete&#xff0c;k8s用控制器创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会恢复到初始状态&#xff0c;一旦回到初始状态&#xff0c;所有的后天编辑的文件都会消失 容器…

rax3000m 刷机 uboot + immortalwrt

0. 环境 - win10 ubuntu22 - rax3000m 生产日期20231027 一台&#xff08;nand版本的&#xff09; 1. 上电&#xff0c;登录web 电脑连接路由器LAN1 http://192.168.10.1/ 账号&#xff1a;user 密码&#xff1a;KK6kYC!3 上网设置&#xff1a;自动获取IP 2. 开启 ssh 2…

Linux CentOS 7.6安装JDK详细保姆级教程

一、检查系统是否自带jdk java --version 如果有的话&#xff0c;找到对应的文件删除 第一步&#xff1a;先查看Linux自带的JDK有几个&#xff0c;用命令&#xff1a; rpm -qa | grep -i java第二步:删除JDK&#xff0c;执行命令&#xff1a; rpm -qa | grep -i java | xarg…

软件测试工程师,从6K到25k的测试之路养成,一路狂飙...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、技术方向 就技…

华为数通HCIA题库(750题)

完整题库在这里&#xff1a;华为数通HCIA-RS题库注释版-加水印.pdf资源-CSDN文库 此处只节选几题。 1.网络管理员在网络中捕获到了一个数据帧&#xff0c;其目的MAC地址是01-00-5E-AO-B1-C3。关于该MAC地址的说法正确的是&#xff08; )。 A.它是一个单播MAC地址 B.它是一个广播…

linux 里面在docker 里面安装pg 数据库(亲测有效)

目录 1 上传 1 上传 上传之后tar 包&#xff0c;将他变成镜像 输入docker images,发现目前是没有镜像的&#xff0c;现在将tar 包变成镜像 docker load -i postgresql.tar以上就将tar 包变成镜像了 现在在宿主机找一个地方&#xff0c;存放数据库的数据 /home/softinstall/…

Unity 实用方法 合集

Unity 实用方法 合集 Unity 打字机效果2D 坐标旋转计算球面坐标求值平滑移动鼠标位置获取2D屏幕坐标转世界坐标物体朝向目标多物体中心点生成本地图片加载画面线框显示画面线框显示 搭载效果 贝塞尔曲线绘制贝塞尔曲线绘制 搭载效果 网格弯曲网格弯曲 搭载效果 Delaunay 模型生…

【FPGA/verilog -入门学习17】vivado 实现串口自发自收程序

1&#xff0c;需求 PC使用串口助手给FPGA板发送9600 波特率的数据&#xff0c;FPGA板接收到数据后&#xff0c;回复同样的数据给PC 2&#xff0c;需求分析 按模块可以划分为&#xff1a; rx接收模块&#xff0c;将输入的8位并行rx 数据转换成[7:0]rx_data 信号&#xff0c;当…

性能优化--实战利用arthas排查java服务cpu占用过高的问题

使用jps -l查看目前的java应用进程 启动arthas&#xff0c;选择需要监控的进程 dashboar查看该应用整体情况 使用thread命令&#xff0c;查看占用cpu过高的几个线程ID 然后使用thread 线程ID查看具体线程在执行哪些内容&#xff0c;可以看到对应的类和方法 正在上传… 重…

K8S实践:非常实用kubectl的别名工具推荐,助你高效工作

转载至我的博客 &#xff0c;公众号&#xff1a;架构成长指南 大家好&#xff0c;我是蜗牛哥&#xff0c;今天介绍一款k8s的别名工具&#xff0c;可以让你高效工作&#xff0c;下面是相关介绍 介绍 我们在管理 Kubernetes集群和执行指定任务是比较复杂和费时的。但是如果使用…

益生菌抗癌?补充这种益生菌,抑制肝癌,还改善肠道健康

撰文 | 宋文法 肠道菌群&#xff0c;是人体不可分割的组成部分&#xff0c;生活在我们肠道内的数万亿细菌对健康起着重要作用&#xff0c;它们影响着人的新陈代谢、消化能力、抵御感染、控制人体对药物的反应&#xff0c;甚至还能预防某些癌症。 非酒精性脂肪肝病&#xff0c;是…

虚幻UE 材质-纹理 1

本篇笔记主要讲两个纹理内的内容&#xff1a;渲染目标和媒体纹理 媒体纹理可以参考之前的笔记&#xff1a;虚幻UE 媒体播放器-视频转成材质-播放视频 所以本篇主要讲两个组件&#xff1a;场景捕获2D、场景捕获立方体 两个纹理&#xff1a;渲染目标、立方体渲染目标 三个功能&am…

构建高效学习平台:企业培训系统源码深度解析

企业培训系统是组织中培养和提升员工技能的核心工具。本文将深入探讨企业培训系统的源码&#xff0c;通过关键技术代码解析&#xff0c;揭示其中的设计原理和功能实现&#xff0c;以构建更高效的学习平台。 1. 环境配置与依赖项安装 首先&#xff0c;让我们关注源码的环境配…

Vue3:Axios配置及使用

Axios官方 一、安装&#xff1a; //使用 npm: $ npm install axios//使用 bower: $ bower install axios//使用 yarn: $ yarn add axios 在package-lock.json文件可以查看axios版本 二、配置&#xff1a; milliaAxios.js 配置axios import axios from axios // 创建一个 ax…

AI老照片修复-Bringing-Old-Photos-Back-to-Life

&#x1f3e1; 个人主页&#xff1a;IT贫道-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;私聊博主加WX好友&#xff0c;获取更多资料哦~ &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你学编程的个人空间-豹哥教你学编程个人主页-哔哩哔哩视频 目录 1. AI老照片修复原理-…

AP5153 低压差 线性降压恒流IC 手电筒LED电源驱动

AP5153 是一种 PWM 调光的、低压 差的 LED 线性降压恒流驱动器。 AP5153 仅需要外接一个电阻和一个 NMOS 管就可以构成一个完整的 LED 恒 流驱动电路&#xff0c; 调节该外接电阻就可以调节 输出电流&#xff0c;输出电流可调范围为 20mA 到 3.0A。 AP5153 还可以通过在 DIM…

怎么修改照片尺寸?来分享3款实用的工具!

在当今的自媒体时代&#xff0c;照片是吸引读者眼球的重要元素之一。有时候&#xff0c;我们需要在不同的平台上传照片&#xff0c;但不同的平台对照片的尺寸要求却不尽相同。为了满足这些要求&#xff0c;我们经常需要修改照片的尺寸。那么&#xff0c;如何快速、准确地修改照…

Linux内核之红黑树详解(2)

该博客结合了维基百科、博客和一些其他的资料&#xff0c;按照理解整理的&#xff0c;如有错误&#xff0c;欢迎指正。 1、创建红黑树&#xff1a; 在实现插入、删除等操作之前&#xff0c;需要先创建一棵红黑树&#xff0c;返回的是红黑树的根结点&#xff1a; RBRoot* crea…

2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷⑤

2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷5 目录 需要竞赛软件包环境以及备赛资源可私信博主&#xff01;&#xff01;&#xff01; 2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷5 模块一 …