首页 > 编程语言 >C++ 与 QML 之间进行数据交互的几种方法

C++ 与 QML 之间进行数据交互的几种方法

时间:2023-10-26 17:13:53浏览次数:33  
标签:const name C++ QObject QML include 交互 Qt

一、属性绑定

这是最简单的方式,可以在QML中直接绑定C++ 对象的属性。通过在C++ 对象中使用Q_PROPERTY宏定义属性,然后在QML中使用绑定语法将属性与QML元素关联起来。

  1. person.h

    #include <QObject>
    
    class Person : public QObject
    {
        Q_OBJECT
        /* 使用 Q_PROPERTY 定义交互的属性 */
        Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
        Q_PROPERTY(int age READ getAge WRITE setAge NOTIFY ageChanged)
    
    public:
        explicit Person(QObject *parent = nullptr)
            : QObject(parent), m_name(""), m_age(0)
        {
        }
    
        /* 为属性提供 getter 和 setter 方法 */
        QString getName() const { return m_name; }
        void setName(const QString& name) { m_name = name; emit nameChanged(); }
    
        int getAge() const { return m_age; }
        void setAge(int age) { m_age = age; emit ageChanged(); }
    
    signals:
        /* 信号与属性对应,通过信号通知其他对象属性的变化 */
        void nameChanged();
        void ageChanged();
    
    private:
        QString m_name;
        int m_age;
    };
    
    
  2. main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include "person.h"
    
    int main(int argc, char *argv[])
    {
        /* 启用Qt应用程序的高DPI缩放功能 */
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        /* 创建一个Qt应用程序的实例 */
        QGuiApplication app(argc, argv);
    
        // 创建Person对象
        Person person;
    
        QQmlApplicationEngine engine;
    
        /* 将Person对象作为QML上下文属性 */
        engine.rootContext()->setContextProperty("person", &person);
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        /* 将 QQmlApplicationEngine 对象的 objectCreated 信号连接到一个 lambda 函数上 */
        /* lambda 函数用于在 QML 文件中的根对象被创建时进行处理,检查对象是否成功创建,如果创建失败则退出应用程序 */
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        /* 加载QML文件并显示用户界面 */
        engine.load(url);
    
        return app.exec();
    }
    
    
    
  3. main.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.5
    
    Window {
        visible: true
        width: 480
        height: 800
        title: qsTr("Hello World")
    
        Column {
            spacing: 10
    
            TextField {
                placeholderText: "请输入姓名"
                text: person.name // 与Person对象的name属性绑定
                onTextChanged: person.name = text // 当文本改变时,更新Person对象的name属性
            }
    
            Slider {
                from: 0
                to: 100
                value: person.age // 与Person对象的age属性绑定
                onValueChanged: person.age = value // 当滑块值改变时,更新Person对象的age属性
            }
    
            Text {
                text: "姓名:" + person.name
            }
    
            Text {
                text: "年龄:" + person.age
            }
        }
    
    }
    
    

二、信号与槽

C++ 对象可以发出信号,而QML中的元素可以连接到这些信号上。这样,当C++ 对象的状态发生变化时,可以通过信号与槽机制将这些变化传递给QML界面。

  1. myobject.h

    #include <QObject>
    #include <QtDebug>
    
    class MyObject : public QObject
    {
        Q_OBJECT
    
    public:
        explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}
    
    signals:
        void mySignal(QString message);
    
    public slots:
        void mySlot(const QString& message) { qDebug() << "Received message from QML:" << message; emit mySignal("Hello from C++");}
    };
    
    
  2. main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include "myobject.h"
    
    int main(int argc, char *argv[])
    {
        /* 启用Qt应用程序的高DPI缩放功能 */
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        /* 创建一个Qt应用程序的实例 */
        QGuiApplication app(argc, argv);
    
        /* 将自定义 C++ 类型注册到 QML 中的函数, 将自定义 C++ 类型注册到 QML 中的函数 */
        qmlRegisterType<MyObject>("com.example", 1, 0, "MyObject");
    
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        /* 将 QQmlApplicationEngine 对象的 objectCreated 信号连接到一个 lambda 函数上 */
        /* lambda 函数用于在 QML 文件中的根对象被创建时进行处理,检查对象是否成功创建,如果创建失败则退出应用程序 */
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        /* 加载QML文件并显示用户界面 */
        engine.load(url);
    
        return app.exec();
    }
    
    
  3. main.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.5
    import com.example 1.0
    
    Window {
        visible: true
        width: 480
        height: 800
        title: qsTr("Hello World")
    
        /* 定义 sendToCpp 信号 */
        signal sendToCpp(string message)
    
        /* Connections 组件用于连接 myObject 的 onMySignal 信号 */
        Connections {
            target: myObject
            onMySignal: console.log("Received message from C++:", message)
        }
    
        MyObject {
            id: myObject
            /* 将 onMySignal 信号传递到 sendToCpp信号上,便于 QML 处理 */
            onMySignal: sendToCpp(message)
        }
    
        Button {
            text: "Send message to C++"
            anchors.centerIn: parent
            /* 单击按钮时,会将信号传递到 C++ 的 mySlot 槽上 */
            onClicked: myObject.mySlot("Hello from QML")
        }
    }
    
    

三、模型视图

模型视图(Model-View):可以使用C++ 中的数据模型(QStandardItemModel)来提供数据给QML界面。QML中的视图元素(如ListView或GridView)可以使用这些模型来显示数据。

  1. mymodel.h

    #ifndef MYMODEL_H
    #define MYMODEL_H
    
    #include <QAbstractListModel>
    #include <QList>
    
    class MyModel : public QAbstractListModel
    {
        Q_OBJECT
    
    public:
        explicit MyModel(QObject *parent = nullptr);
    
        enum {
            NameRole = Qt::UserRole + 1,
            AgeRole,
            EmailRole
        };
    
        // 重写以下几个虚函数
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
        QHash<int, QByteArray> roleNames() const override;
    
    private:
        struct Person {
            QString name;
            int age;
            QString email;
        };
    
        QList<Person> m_persons;
    };
    
    #endif // MYMODEL_H
    
  2. mymodel.cpp

    #include "mymodel.h"
    
    MyModel::MyModel(QObject *parent)
        : QAbstractListModel(parent)
    {
        // 初始化一些数据
        m_persons.append({"Alice", 25, "[email protected]"});
        m_persons.append({"Bob", 30, "[email protected]"});
        m_persons.append({"Charlie", 35, "[email protected]"});
    }
    
    int MyModel::rowCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent);
        return m_persons.count();
    }
    
    QVariant MyModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid())
            return QVariant();
    
        if (index.row() >= m_persons.count() || index.row() < 0)
            return QVariant();
    
        const Person &person = m_persons[index.row()];
        if (role == NameRole)
            return person.name;
        else if (role == AgeRole)
            return person.age;
        else if (role == EmailRole)
            return person.email;
    
        return QVariant();
    }
    
    QHash<int, QByteArray> MyModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
        roles[NameRole] = "name";
        roles[AgeRole] = "age";
        roles[EmailRole] = "email";
        return roles;
    }
    
    
  3. main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include "mymodel.h"
    
    int main(int argc, char *argv[])
    {
        /* 启用Qt应用程序的高DPI缩放功能 */
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        /* 创建一个Qt应用程序的实例 */
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        MyModel myModel;
        engine.rootContext()->setContextProperty("myModel", &myModel);
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        /* 将 QQmlApplicationEngine 对象的 objectCreated 信号连接到一个 lambda 函数上 */
        /* lambda 函数用于在 QML 文件中的根对象被创建时进行处理,检查对象是否成功创建,如果创建失败则退出应用程序 */
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        /* 加载QML文件并显示用户界面 */
        engine.load(url);
    
        return app.exec();
    }
    
    
  4. main.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.5
    
    Window {
        visible: true
        width: 480
        height: 800
        title: qsTr("Hello World")
    
        ListView {
            anchors.fill: parent
            model: myModel
            delegate: Item {
                width: parent.width
                height: 60
                Column {
                    Text { text: name }
                    Text { text: age }
                    Text { text: email }
                }
            }
        }
    }
    
    
  5. 运行效果

四、QML类型注册

QML类型注册(QML Type Registration):可以将C++ 对象注册为自定义的QML类型,使得QML可以直接创建和使用这些对象。通过在C++ 中使用 Q_PROPERTY 宏和 Q_INVOKABLE 函数,可以将C++ 类注册为QML类型。我需要这样一个案例

  1. myobject.h

    #include <QQmlEngine>
    #include "QDebug"
    
    class MyObject : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    public:
        explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}
        QString name() const { return m_name; }
        void setName(const QString &name) { m_name = name; emit nameChanged(); }
        Q_INVOKABLE void printName() { qDebug() << "Name:" << m_name; }
    
        static void registerQmlType()
        {
            qmlRegisterType<MyObject>("com.example", 1, 0, "MyObject");
        }
    
    signals:
        void nameChanged();
    private:
        QString m_name;
    };
    
    
  2. main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include "myobject.h"
    
    int main(int argc, char *argv[])
    {
        /* 启用Qt应用程序的高DPI缩放功能 */
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        /* 创建一个Qt应用程序的实例 */
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        MyObject::registerQmlType();
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        /* 将 QQmlApplicationEngine 对象的 objectCreated 信号连接到一个 lambda 函数上 */
        /* lambda 函数用于在 QML 文件中的根对象被创建时进行处理,检查对象是否成功创建,如果创建失败则退出应用程序 */
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        /* 加载QML文件并显示用户界面 */
        engine.load(url);
    
        return app.exec();
    }
    
    
  3. main.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.5
    import com.example 1.0
    
    Window {
        visible: true
        width: 480
        height: 800
        title: qsTr("Hello World")
    
        MyObject {
            id: myObject
            name: "John"
        }
    
        /* 垂直布置组件 */
        Column {
            anchors.fill: parent        // 大小为父组件的大小
            anchors.margins: 40         // 与父组件四周的间隔
            spacing: 10                 // 子组件之间的间隔
    
            Text {
                text: myObject.name
            }
    
            Button {
                text: "Print Name"
                onClicked: myObject.printName()
            }
        }
    }
    

标签:const,name,C++,QObject,QML,include,交互,Qt
From: https://www.cnblogs.com/jzcn/p/17774676.html

相关文章

  • PLC、触摸屏、上位机之间如何实现无线数据交互功能?
    本文以组态王与西门子触摸屏和2台西门子S7-200SMART为例,介绍组态王、触摸屏与多台PLC在Profinet协议下的自组网无线通信实现过程。在本方案中采用了西门子PLC无线通讯终端——DTD418M,作为实现无线通讯的硬件设备。我们无需更改网络参数和原有程序,也不必了解协议细节,通过欧美系PLC......
  • c++中的继承(下)
    首先我们先回忆一下,在派生类(子类)中默认的成员函数做了什么事情?我们现在可以这么认为对于普通类来说呢?只需要看待两个部分的成员:内置类型和自定义类型。而对于派生类而言序言看待三个部分的成员:内置类型,自定义类型以及父类类型构造和析构拷贝构造普通类对于内置类型一般不处理,自定类......
  • Ajax异步交互技术
    概念:AsynchronousJavaScriptAndXML,异步的JavaScript和XML。作用:数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用的校验等等。 原生......
  • C++修饰符类型
    C++允许在char、int和double数据类型前放置修饰符。修饰符用于改变基本类型的含义,所以它更能满足各种情境的需求。当前有以下几种数据类型修饰符:signedunsignedlongshort修饰符signed、unsigned、long和short可应用于整型,signed和unsigned可应用于字符型,long可应用于双精度......
  • 【每日例题】 蓝桥杯 c++ 考勤刷卡
    考勤刷卡题目小蓝负责一个公司的考勤系统,他每天都需要根据员工刷卡的情况来确定每个员工是否到岗。当员工刷卡时,会在后台留下一条记录,包括刷卡的时间和员工编号,只要在—天中员工刷过—次卡,就认为他到岗了。现在小蓝导出了—天中所有员工的刷卡记录,请将所有到岗员工的员工......
  • 现代C++语言核心特性解析 谢丙堃​ 2021年pdf电子版
    现代C++语言核心特性解析2021年pdf电子版作者: 谢丙堃出版年: 2021-10ISBN: 9787115564177连接提取码:ckop自从C++11发布,就没有系统学习C++的书,也很久没有看国内作者出的C++书籍了。市面上对于现代C++的书很少,这是一本讲述现代C++11~C++20的书。意外,写得不错,容易理解,难得是除了......
  • C++中vector容器详解
    参考链接:https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html一、什么是vector?向量(Vector)是一个封装了动态大小数组的顺序容器(SequenceContainer)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。二......
  • 引用C++程序,在DOS命令行打印彩色玫瑰花
    python代码:fromctypesimport*importpygameimportrandomimportstringimporttimeif__name__=='__main__':withopen('log.txt','rb')asf:lines=f.readlines()count=0forlineinlines:......
  • 【踩坑】/usr/bin/ld: cannot find -lstdc++: No such file or directory
    环境:win10中的wsl2的Ubuntu1.报错/usr/bin/ld:cannotfind-lstdc++:Nosuchfileordirectory通过sudoapt-getinstalllibstdc++6解决。2.安装完之后依旧还是报一样的错参考资料通过gcc-lstdc++--verbose检查。输出了一大堆东西,但在末尾还是有/usr/b......
  • C++封装数据结构
    1.概论C++STL之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector,string,list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作。vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以......