一、属性绑定

这是最简单的方式,可以在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, "alice@example.com"});
    m_persons.append({"Bob", 30, "bob@example.com"});
    m_persons.append({"Charlie", 35, "charlie@example.com"});
    } 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()
    }
    }
    }

C++ 与 QML 之间进行数据交互的几种方法的更多相关文章

  1. Androidclient和server端数据交互的第一种方法

    网上有非常多样例来演示Android客户端和server端数据怎样实现交互只是这些样例大多比較繁杂,对于刚開始学习的人来说这是不利的.如今介绍几种代码简单.逻辑清晰的交互样例,本篇博客介绍第一种: 一 ...

  2. Vue2.0父子组件之间和兄弟组件之间的数据交互

    熟悉了Vue.js的同级组件之间通信,写此文章,以便记录. Vue是一个轻量级的渐进式框架,对于它的一些特性和优点,请在官网上进行查看,不再赘述. 使用NPM及相关命令行工具初始化的Vue工程,目录结 ...

  3. vuejs组件交互 - 01 - 父子组件之间的数据交互

    父子组件之间的数据交互遵循: props down - 子组件通过props接受父组件的数据 events up - 父组件监听子组件$emit的事件来操作数据 示例 子组件的点击事件函数中$emit ...

  4. 基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

    在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理.本文主要介绍利用Jquery处理数据交互的几种方式,包括 ...

  5. web实现数据交互的几种常见方式

    前言 在当今社会,作为一名前端程序猿,并不是一昧的去制作静态页面就可以满足滴:你说你会制作网页,好吧,只能说你算是一个前端程序猿.但这是你作为一个程序猿最基本的能力,并不会为你进行加分: 我们都明白, ...

  6. (转)基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

    http://www.cnblogs.com/wuhuacong/p/4085682.html 在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交, ...

  7. Android数据存储的五种方法汇总

    本文介绍Android中的5种数据存储方式. 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 ...

  8. Android之数据存储的五种方法

    1.Android数据存储的五种方法 (1)SharedPreferences数据存储 详情介绍:http://www.cnblogs.com/zhangmiao14/p/6201900.html 优 ...

  9. IOS开发中数据持久化的几种方法--NSUserDefaults

    IOS开发中数据持久化的几种方法--NSUserDefaults IOS 开发中,经常会遇到需要把一些数据保存在本地的情况,那么这个时候我们有以下几种可以选择的方案: 一.使用NSUserDefaul ...

  10. oracle rename数据文件的两种方法

    oracle rename数据文件的两种方法 2012-12-11 20:44 10925人阅读 评论(0) 收藏 举报  分类: oracle(98)  版权声明:本文为博主原创文章,未经博主允许不 ...

随机推荐

  1. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-6-元素定位大法-下篇

    1.简介 上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的定位方法的理论基础知识以及在什么情况下推荐使用.今天这一篇讲解和分享一下,在日常中很少用到或者很少见的定位 ...

  2. 即构SDK9月迭代:外部采集、音频频谱、房间附加消息等多个模块功能上新

    即构SDK9月迭代来了,本月SDK在外部采集.音频频谱.房间附加消息等多个功能模块均有新功能上线,并且还针对K歌音乐场景下,优化了变调功能效果.以下是详细的迭代内容: LiveRoom   新增 1. ...

  3. maven项目创建后添加resources等文件夹

    maven项目初始化只生成src/main/resources目录,但是这个不够用,我们得创建 src/main/java目录 src/test/java目录 src/test/resources目录 ...

  4. jdbc-plus是一款基于JdbcTemplate增强工具包,基于JdbcTemplate已实现分页、多租户、动态表名等插件,可与mybatis、mybatis-plus等混合使用

    jdbc-plus简介 jdbc-plus是一款基于JdbcTemplate增强工具包,基于JdbcTemplate已实现分页.多租户.动态表名等插件,可与mybatis.mybatis-plus等混 ...

  5. 2023年郑州轻工业大学校赛邀请赛myh

    赛程回顾和赛后总结 赛程回顾 although 昨天刚复盘的,但还是记不住题号.就口胡下是那类型题吧. 刚开始时,我和队长先看的a,让jc去找签到题.我们看了下a,队长说可能dp,但还是感觉没啥思路就 ...

  6. 基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发2-功能开发

    基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发2-功能开发 项目简介:目标是开发一个跨平台的AI聊天和其他功能的客户端平台.目的来学习和了解Avalonia.将这个项目部署 ...

  7. PWM点灯

    目录 PWM脉冲宽调点灯 前言 1.什么是PWM 2.PWM的实现 3.PWM实现步骤(通用定时器) 3.1 打开定时器的时钟 3.2 配置端口 3.3 设置定时器 3.4 设置PWM 3.5 完整代 ...

  8. Linux 命令:time

    参考链接: time 命令

  9. Winform跨线程访问UI

    在开发winfrom应用时,经常遇到异常:System.InvalidOperationException:"线程间操作无效: 从不是创建控件"xxxx"的线程访问它.出 ...

  10. 【译】Silverlight 不会消亡 XAML for Blazor 到来

    Userware 正在使用早已消失的.令人怀念的微软 Silverlight Web 开发平台的遗留来支持其新的"XAML for Blazor"产品,该产品允许 .NET 开发人 ...