当前位置: 首页 > news >正文

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类型。我需要这样一个案例

  1. 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 一、属性绑定 这是最简单的方式&#xff0c;可以在QML中直接绑定C 对象的属性。通过在C 对象中使用Q_PROPERTY宏定义属性&#xff0c;然后在QML中使用绑定语法将属性与QML元素关联起来。 1. person.h #include <QObject&g…...

Javaweb学习之Vue项目的创建(二)

学习资料 Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org) 准备工作都做完了&#xff0c;接下来开始Vue的正式学习。 第一步&#xff0c;打开VS Code 在VS Code里&#xff0c;我们也需要使用到终端&#xff0c;如果不是以管理员身份打开&#xff0c;在新建Vue项目的时候…...

『深度长文』4种有效提高LLM输出质量的方法!

LLM&#xff0c;全称Large Language Model&#xff0c;意为大型语言模型&#xff0c;是一种基于深度学习的AI技术&#xff0c;能够生成、理解和处理自然语言文本&#xff0c;也因此成为当前大多数AI工具的核心引擎。LLM通过学习海量的文本数据&#xff0c;掌握了词汇、语法、语…...

【工业机器人】工业异常检测大模型AnomalyGPT

AnomalyGPT 工业异常检测视觉大模型AnomalyGPT AnomalyGPT: Detecting Industrial Anomalies using Large Vision-Language Models AnomalyGPT是一种基于大视觉语言模型&#xff08;LVLM&#xff09;的新型工业异常检测&#xff08;IAD&#xff09;方法。它利用LVLM的能力来理…...

【PGCCC】PostgreSQL案例:planning time超长问题分析#PG初级

在使用 PostgreSQL 时&#xff0c;查询的执行计划&#xff08;planning time&#xff09;有时会出现异常长的情况&#xff0c;这可能会影响数据库的整体性能。分析和解决这种问题可以从多个角度入手&#xff0c;以下是常见原因和相应的解决思路&#xff1a; 1. 统计信息不准确…...

【图文并茂】ant design pro 如何给后端发送 json web token - 请求拦截器的使用

上一节有讲过 【图文并茂】ant design pro 如何对接后端个人信息接口 还差一个东西&#xff0c;去获取个人信息的时候&#xff0c;是要发送 token 的&#xff0c;不然会报 403. 就是说在你登录之后才去获得个人信息。这样后端才能知道是谁的信息。 token 就代码了某个人。 …...

【微信小程序】自定义组件 - behaviors

1. 什么是 behaviors 2. behaviors 的工作方式 3. 创建 behavior 调用 Behavior(Object object) 方法即可创建一个共享的 behavior 实例对象&#xff0c;供所有的组件使用&#xff1a; 4. 导入并使用 behavior 5. behavior 中所有可用的节点 6. 同名字段的覆盖和组合规则* 关…...

Linux ubuntu 24.04 安装运行《帝国时代3》免安装绿色版游戏,解决 “Could not load DATAP.BAR”等问题

Linux ubuntu 24.04 安装运行《帝国时代3》游戏&#xff0c;解决 “Could not load DATAP.BAR" 等问题 《帝国时代 3》是一款比较经典的即时战斗游戏&#xff0c;伴随了我半个高中时代&#xff0c;周末有时间就去泡网吧&#xff0c;可惜玩的都是简单人机&#xff0c;高难…...

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实验室管理系统如何实现数据自动采集

随着科研技术的不断发展&#xff0c;LIMS实验室管理系统的应用也愈来愈广&#xff0c;已经成为现代化实验室管理不可或缺的工具。LIMS实验室管理系统未与仪器设备对接前&#xff0c;仪器设备产生的数据都是通过人工录入到系统中&#xff0c;再经过人工审核形成最终的数据报告。…...

全自动商用油炸锅介绍:

全自动商用油炸锅‌是一种专门为商业用途设计的厨房设备&#xff0c;旨在高效、节能、卫生地完成大量食品的油炸加工。这种设备通常采用油水混合技术&#xff0c;能够自动过滤残渣&#xff0c;延长换油周期&#xff0c;从而大大降低用油成本。全自动商用油炸锅适合中、小型油炸…...

CE修改器的简单使用

前言 这个系列目前是出于兴趣爱好&#xff0c;最终目的是为了可以用代码控制修改单机游戏。 这篇文章的对象是《植物大战僵尸杂交版》&#xff0c;其余游戏类似。 博客仅做技术研究使用&#xff0c;禁止用作商业用途。 1&#xff0c;安装CE修改器 到官网进行下载&#xff…...

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有两种密码方式&#xff0c;一种是打开后进入文件内容页面后需要密码才能进行修改等操作&#xff0c;网上有很多方式进行移除密码操作&#xff0c;第二种是打开就需要密码&#xff0c;我这里简单记录一个暴力破解的方式&#xff0c;仅供参考 import PyPDF2 import itertools…...

从bbl和overleaf版本解决Arxiv提交后缺失参考文献Citation on page undefined on input line

debug 食用指南&#xff1a;框架/语言&#xff1a;问题描述&#xff1a;解决方案&#xff1a;问题原因&#xff1a;版本解决方案&#xff1a; 安利时间&#xff1a; 食用指南&#xff1a; 框架使用过程中的问题首先要注意版本发布时间造成方法弃用 当你在CSDN等网站查找不到最…...

Flutter【01】状态管理

声明式编程 Flutter 应用是 声明式 的&#xff0c;这也就意味着 Flutter 构建的用户界面就是应用的当前状态。 当你的 Flutter 应用的状态发生改变时&#xff08;例如&#xff0c;用户在设置界面中点击了一个开关选项&#xff09;你改变了状态&#xff0c;这将会触发用户界面…...

(转载)使用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语言的时候&#xff0c;有没有遇见过类似于下面这样的代码呢&#xff1f; // 整形转bool int count 10; while(count--) {cout << count << endl; }// 指针转bool int* ptr cur; while(ptr) {//…… } 众所周知&#xff0c;while循环的判断…...

嵌入式AI快速入门课程-K510篇 (第三篇 环境搭建及开发板操作)

第三篇 环境搭建及开发板操作 文章目录 第三篇 环境搭建及开发板操作1.配置VMware使用桥接网卡1.1 vmware设置1.2 虚拟网络编辑器设置 2.安装软件2.2 安装 Windows 软件2.3 使用MobaXterm远程登录Ubuntu2.4 使用FileZilla在Windows和Ubuntu之间传文件2.5编程示例&#xff1a;Ub…...

C++第三十九弹---C++ STL中的无序容器:unordered_set与unordered_map使用详解

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【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…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

FTXUI::Dom 模块

DOM 模块定义了分层的 FTXUI::Element 树&#xff0c;可用于构建复杂的终端界面&#xff0c;支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...

数据挖掘是什么?数据挖掘技术有哪些?

目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...

Python打卡训练营学习记录Day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...