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

这篇具有很好参考价值的文章主要介绍了【qml-1】第一次尝试qml与c++交互。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景:

【qml-2】尝试一个有模式的qml弹窗-CSDN博客

目的是学习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-1】第一次尝试qml与c++交互,qt/c++,c++,交互,qt,qml

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

【qml-1】第一次尝试qml与c++交互,qt/c++,c++,交互,qt,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++信号中的形参名。

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

本文完。文章来源地址https://www.toymoban.com/news/detail-803173.html

到了这里,关于【qml-1】第一次尝试qml与c++交互的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt开发教程:C++与QML的交互

    Qt是一个功能强大的跨平台应用程序开发框架,支持同时使用C++和QML来开发应用程序。通过C++与QML的交互,我们可以实现更灵活、更强大的应用程序。本文将详细介绍如何在Qt中创建自定义对象、在QML端发送信号并绑定到C++端、在C++端发送信号并绑定到QML端、以及实现QML端直接

    2024年04月16日
    浏览(46)
  • 在Qt中实现C++与QML的交互

    Qt是一个功能强大的跨平台应用程序开发框架,支持同时使用C++和QML来开发应用程序。通过C++与QML的交互,我们可以实现更灵活、更强大的应用程序。本文将详细介绍如何在Qt中创建自定义对象、在QML端发送信号并绑定到C++端、在C++端发送信号并绑定到QML端、以及实现QML端直接

    2024年02月09日
    浏览(34)
  • qt笔记之qml和C++的交互系列(一):初记

    code review! —— 杭州 2023-11-16 夜 参考资料: 官方文档《Exposing Attributes of C++ Types to QML》(将C++类暴露给QML) 官方文档《Data Type Conversion Between QML and C++》 官方文档《The Property System》 官方文档《Defining QML Types from C++》(在QML中定义C++类) 官方文档《Overview - QML and C++ Integration》 1.

    2024年02月04日
    浏览(34)
  • python 第一次作业

    因为笔者有一些 c/c++ 语言的基础,所以应该学 python 会稍微简单一些 输入的时候所有的输入都是字符串类型,我们需要进行类型转换 参见资源里面的第三题和第四题,为了方便起见,直接把代码贴在下面

    2024年03月25日
    浏览(41)
  • docker第一次作业

    docker第一次作业 1.安装docker服务,配置镜像加速器  yum install -y yum-utils device-mapper-persistent-data lvm2 y um-config-manager --add-repo https: //mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i \\\'s+download.docker.com+mirrors.aliyun.com/docker-ce+\\\'  /etc/yum.repos.d/docker-ce.repo yum makecache fast yum -y install docke

    2024年02月12日
    浏览(33)
  • 第一次面试复盘

    这个秋招到目前为止第一次拿到了面试机会,虽然是小公司,但是人家是有官网的!!!很爱!先赶紧复盘一下,因为还有很多笔试没有复盘。 你们的数学建模解决了什么问题?你觉得你们为什么能拿到这个成绩 说下对java这门语言的了解 它是一种面向对象的编程语言,所以

    2024年01月22日
    浏览(34)
  • 树莓派第一次开机

    树莓派由英国的树莓派基金会发行,旨在通过发行这个廉价开源的可随意破解的微型计算机,推动中小学编程教育,发行之后很快在全世界的开源创客圈中流行。截止到2018年10月,最新版本的树莓派主板是3B+,国内某宝上卖230元左右,还有更微型的树莓派主板Zero,国内某宝卖

    2024年02月13日
    浏览(36)
  • 第一次PR经历

         

    2024年02月13日
    浏览(30)
  • shell第一次作业

    1、判断当前磁盘剩余空间是否有20G,如果小于20G,则将报警邮件发送给管理员,每天检查次磁盘剩余空间。 2、判断web服务是否运行    1、查看进程的方式判断该程序是否运行,    2、通过查看端口的方式判断该程序是否运行,如果没有运行,则启动该服务并配置防火墙规

    2024年02月09日
    浏览(37)
  • 第一次博客作业

    这学期才开始接触Java,之前只学了C语言,所以一开始写题目的代码的时候对Java的众多函数和语法不是太熟悉,一开始就上手写代码有点不适应。 ​  关于类: 1、类似C中的struct,构造函数、内置方法(函数 )都比较相似 2、尽量避免代码的重复,把private和public的方法搞清晰。

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包