C++ 与 QML 之间进行数据交互的几种方法
https://www.cnblogs.com/jzcn/p/17774676.html
一、属性绑定
这是最简单的方式,可以在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.5Window {visible: truewidth: 480height: 800title: qsTr("Hello World")Column {spacing: 10TextField {placeholderText: "请输入姓名"text: person.name // 与Person对象的name属性绑定onTextChanged: person.name = text // 当文本改变时,更新Person对象的name属性}Slider {from: 0to: 100value: 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_OBJECTpublic: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.0Window {visible: truewidth: 480height: 800title: qsTr("Hello World")/* 定义 sendToCpp 信号 */signal sendToCpp(string message)/* Connections 组件用于连接 myObject 的 onMySignal 信号 */Connections {target: myObjectonMySignal: 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_OBJECTpublic: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.5Window {visible: truewidth: 480height: 800title: qsTr("Hello World")ListView {anchors.fill: parentmodel: myModeldelegate: Item {width: parent.widthheight: 60Column {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类型。我需要这样一个案例
-
myobject.h
#include <QQmlEngine>
#include "QDebug"class MyObject : public QObject
{Q_OBJECTQ_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.0Window {visible: truewidth: 480height: 800title: qsTr("Hello World")MyObject {id: myObjectname: "John"}/* 垂直布置组件 */Column {anchors.fill: parent // 大小为父组件的大小anchors.margins: 40 // 与父组件四周的间隔spacing: 10 // 子组件之间的间隔Text {text: myObject.name}Button {text: "Print Name"onClicked: myObject.printName()}}
}相关文章:
C++ 与 QML 之间进行数据交互的几种方法
https://www.cnblogs.com/jzcn/p/17774676.html 一、属性绑定 这是最简单的方式,可以在QML中直接绑定C 对象的属性。通过在C 对象中使用Q_PROPERTY宏定义属性,然后在QML中使用绑定语法将属性与QML元素关联起来。 1. person.h #include <QObject&g…...
Javaweb学习之Vue项目的创建(二)
学习资料 Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org) 准备工作都做完了,接下来开始Vue的正式学习。 第一步,打开VS Code 在VS Code里,我们也需要使用到终端,如果不是以管理员身份打开,在新建Vue项目的时候…...
『深度长文』4种有效提高LLM输出质量的方法!
LLM,全称Large Language Model,意为大型语言模型,是一种基于深度学习的AI技术,能够生成、理解和处理自然语言文本,也因此成为当前大多数AI工具的核心引擎。LLM通过学习海量的文本数据,掌握了词汇、语法、语…...
【工业机器人】工业异常检测大模型AnomalyGPT
AnomalyGPT 工业异常检测视觉大模型AnomalyGPT AnomalyGPT: Detecting Industrial Anomalies using Large Vision-Language Models AnomalyGPT是一种基于大视觉语言模型(LVLM)的新型工业异常检测(IAD)方法。它利用LVLM的能力来理…...
【PGCCC】PostgreSQL案例:planning time超长问题分析#PG初级
在使用 PostgreSQL 时,查询的执行计划(planning time)有时会出现异常长的情况,这可能会影响数据库的整体性能。分析和解决这种问题可以从多个角度入手,以下是常见原因和相应的解决思路: 1. 统计信息不准确…...
【图文并茂】ant design pro 如何给后端发送 json web token - 请求拦截器的使用
上一节有讲过 【图文并茂】ant design pro 如何对接后端个人信息接口 还差一个东西,去获取个人信息的时候,是要发送 token 的,不然会报 403. 就是说在你登录之后才去获得个人信息。这样后端才能知道是谁的信息。 token 就代码了某个人。 …...
【微信小程序】自定义组件 - behaviors
1. 什么是 behaviors 2. behaviors 的工作方式 3. 创建 behavior 调用 Behavior(Object object) 方法即可创建一个共享的 behavior 实例对象,供所有的组件使用: 4. 导入并使用 behavior 5. behavior 中所有可用的节点 6. 同名字段的覆盖和组合规则* 关…...
Linux ubuntu 24.04 安装运行《帝国时代3》免安装绿色版游戏,解决 “Could not load DATAP.BAR”等问题
Linux ubuntu 24.04 安装运行《帝国时代3》游戏,解决 “Could not load DATAP.BAR" 等问题 《帝国时代 3》是一款比较经典的即时战斗游戏,伴随了我半个高中时代,周末有时间就去泡网吧,可惜玩的都是简单人机,高难…...
Springboot 图片
Springboot 图片 因为 server.servlet.context-path: /api 所以 url是这个的时候 http://127.0.0.1:9100/api/staticfiles/image/dd56a59d-da84-441a-8dac-1d97f9e42090.jpeg 配置代码的前面的 /api 是不要写的 package com.gk.study.config;import org.springframework.conte…...
LIMS实验室管理系统如何实现数据自动采集
随着科研技术的不断发展,LIMS实验室管理系统的应用也愈来愈广,已经成为现代化实验室管理不可或缺的工具。LIMS实验室管理系统未与仪器设备对接前,仪器设备产生的数据都是通过人工录入到系统中,再经过人工审核形成最终的数据报告。…...
全自动商用油炸锅介绍:
全自动商用油炸锅是一种专门为商业用途设计的厨房设备,旨在高效、节能、卫生地完成大量食品的油炸加工。这种设备通常采用油水混合技术,能够自动过滤残渣,延长换油周期,从而大大降低用油成本。全自动商用油炸锅适合中、小型油炸…...
CE修改器的简单使用
前言 这个系列目前是出于兴趣爱好,最终目的是为了可以用代码控制修改单机游戏。 这篇文章的对象是《植物大战僵尸杂交版》,其余游戏类似。 博客仅做技术研究使用,禁止用作商业用途。 1,安装CE修改器 到官网进行下载ÿ…...
element-plus el-cascader懒加载怎么指定对应的label和value。最后一级怎么判断?
<el-cascader:props"props"placeholder"请选择现地址所在地"v-model"currentaddress"ref"currentaddressRef"change"currentaddressChange"style"width:100%"clearable/> 懒加载需要用到props。 const pro…...
pdf查看密码
pdf有两种密码方式,一种是打开后进入文件内容页面后需要密码才能进行修改等操作,网上有很多方式进行移除密码操作,第二种是打开就需要密码,我这里简单记录一个暴力破解的方式,仅供参考 import PyPDF2 import itertools…...
从bbl和overleaf版本解决Arxiv提交后缺失参考文献Citation on page undefined on input line
debug 食用指南:框架/语言:问题描述:解决方案:问题原因:版本解决方案: 安利时间: 食用指南: 框架使用过程中的问题首先要注意版本发布时间造成方法弃用 当你在CSDN等网站查找不到最…...
Flutter【01】状态管理
声明式编程 Flutter 应用是 声明式 的,这也就意味着 Flutter 构建的用户界面就是应用的当前状态。 当你的 Flutter 应用的状态发生改变时(例如,用户在设置界面中点击了一个开关选项)你改变了状态,这将会触发用户界面…...
(转载)使用zed相机录制视频
参照下面这个链接 https://blog.csdn.net/peng_258/article/details/127457199?ops_request_misc&request_id&biz_id102&utm_termzed2%E5%BD%95%E5%88%B6%E6%95%B0%E6%8D%AE%E9%9B%86&utm_mediumdistribute.pc_search_result.none-task-blog-2~all~sobaiduweb…...
C/C++中奇妙的类型转换
1.引言 大家在学习C语言的时候,有没有遇见过类似于下面这样的代码呢? // 整形转bool int count 10; while(count--) {cout << count << endl; }// 指针转bool int* ptr cur; while(ptr) {//…… } 众所周知,while循环的判断…...
嵌入式AI快速入门课程-K510篇 (第三篇 环境搭建及开发板操作)
第三篇 环境搭建及开发板操作 文章目录 第三篇 环境搭建及开发板操作1.配置VMware使用桥接网卡1.1 vmware设置1.2 虚拟网络编辑器设置 2.安装软件2.2 安装 Windows 软件2.3 使用MobaXterm远程登录Ubuntu2.4 使用FileZilla在Windows和Ubuntu之间传文件2.5编程示例:Ub…...
C++第三十九弹---C++ STL中的无序容器:unordered_set与unordered_map使用详解
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 目录 1 unordered_set 1.1 unordered_set的接口说明 1.1.1 unordered_set的构造 1.1.2. unordered_set的容量 1.1.3. unordered_set的迭代器 1.1…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
