C++ 与 QML 之间进行数据交互的几种方法
一、属性绑定
这是最简单的方式,可以在QML中直接绑定C++ 对象的属性。通过在C++ 对象中使用Q_PROPERTY宏定义属性,然后在QML中使用绑定语法将属性与QML元素关联起来。
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;
};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();
}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界面。
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++");}
};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();
}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)可以使用这些模型来显示数据。

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
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;
}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();
}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 }
}
}
}
}运行效果

四、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_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;
};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();
}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 之间进行数据交互的几种方法的更多相关文章
- Androidclient和server端数据交互的第一种方法
网上有非常多样例来演示Android客户端和server端数据怎样实现交互只是这些样例大多比較繁杂,对于刚開始学习的人来说这是不利的.如今介绍几种代码简单.逻辑清晰的交互样例,本篇博客介绍第一种: 一 ...
- Vue2.0父子组件之间和兄弟组件之间的数据交互
熟悉了Vue.js的同级组件之间通信,写此文章,以便记录. Vue是一个轻量级的渐进式框架,对于它的一些特性和优点,请在官网上进行查看,不再赘述. 使用NPM及相关命令行工具初始化的Vue工程,目录结 ...
- vuejs组件交互 - 01 - 父子组件之间的数据交互
父子组件之间的数据交互遵循: props down - 子组件通过props接受父组件的数据 events up - 父组件监听子组件$emit的事件来操作数据 示例 子组件的点击事件函数中$emit ...
- 基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式
在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理.本文主要介绍利用Jquery处理数据交互的几种方式,包括 ...
- web实现数据交互的几种常见方式
前言 在当今社会,作为一名前端程序猿,并不是一昧的去制作静态页面就可以满足滴:你说你会制作网页,好吧,只能说你算是一个前端程序猿.但这是你作为一个程序猿最基本的能力,并不会为你进行加分: 我们都明白, ...
- (转)基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式
http://www.cnblogs.com/wuhuacong/p/4085682.html 在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交, ...
- Android数据存储的五种方法汇总
本文介绍Android中的5种数据存储方式. 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 ...
- Android之数据存储的五种方法
1.Android数据存储的五种方法 (1)SharedPreferences数据存储 详情介绍:http://www.cnblogs.com/zhangmiao14/p/6201900.html 优 ...
- IOS开发中数据持久化的几种方法--NSUserDefaults
IOS开发中数据持久化的几种方法--NSUserDefaults IOS 开发中,经常会遇到需要把一些数据保存在本地的情况,那么这个时候我们有以下几种可以选择的方案: 一.使用NSUserDefaul ...
- oracle rename数据文件的两种方法
oracle rename数据文件的两种方法 2012-12-11 20:44 10925人阅读 评论(0) 收藏 举报 分类: oracle(98) 版权声明:本文为博主原创文章,未经博主允许不 ...
随机推荐
- MyBatis实现动态SQL更新
博主记得在一个周五快下班的下午,产品找到我(为什么总感觉周五快下班就来活 ),跟我说有几个业务列表查询需要加上时间条件过滤数据,这个条件可能会变,不保证以后不修改,这个改动涉及到多个列表查询,于是博主 ...
- PB从入坑到放弃(五)窗口使用技巧
PB应用程序就是由许多共同协作完成特定任务的窗口组成的集合. 窗口在应用程序的开发工作中占有很大的比重,是非常重要的一个 PB 对象 一.窗口类型 窗口类型 描述 Main ①可以覆盖其他窗口,也可以 ...
- Oracle快速拷贝数据
游标拷贝数据 根据条件进行数据拷贝 -- 游标方式拷贝数据 DECLARE CURSOR cur IS SELECT * FROM JACKPOT WHERE TO_CHAR(JACKPOT.CREA ...
- 【MAUI Blazor踩坑日记】1.关于图标的处理
前言 本系列文章,默认你已经踏上了MAUI Blazor的贼船,并且对MAUI Blazor有了一些了解,知道MAUI是什么,知道Blazor是什么. 不会教你怎么写MAUI Blazor的项目,只是 ...
- sql注入-基于pikachu靶场学习之SQL注入
sql注入(pikachu靶场学习之SQL注入) 环境准备 环境:wmware,安装两台win10的虚拟机在服务器上部署服务,在客户机上进行安全测试 声明:不涉及互联网上的资源,学习都在内网完成,一切 ...
- 2021-7-30 MySql进阶2
创建临时表只需在table前面加temporary CREATE TEMPORARY TABLE mytable#创建临时表,在断开数据库连接时销毁 ( ID INT NOT NULL, userna ...
- 【overcome error】dereferencing pointer to incomplete type
@ 目录 前言 解决 代码情况 分析问题 尾声 前言 这个问题是我在学习数据结构链栈部分遇到的,英文报错如题所示,中文意思是:取消引用不完整类型的指针,在百度一圈也没明白,(百度搜索,看一个和全看基本 ...
- Proxmox VE软件防火墙的配置
1 软件防火墙的基本概念 防火墙是计算机网络中用于保护网络安全的关键技术.防火墙可以是硬件设备部署在网络出口,也可以是软件部署在终端设备出口.本文主要介绍软件防火墙. 软件防火墙可以根据网络流量的方向 ...
- linux设置信号量系统参数
前言 信号量是IPC(进程间通信)机制的一种,用于协调多个进程或线程对共享数据的读写操作,本质上是一个计数器.类似于锁,主要用于保护共享资源,控制同时访问资源的进程数. 信号量只允许调用者对它进行等待 ...
- 【技术积累】Linux中的命令行【理论篇】【六】
as命令 命令介绍 在Linux中,as命令是一个汇编器,用于将汇编语言源代码转换为可执行的目标文件.它是GNU Binutils软件包的一部分,提供了一系列用于处理二进制文件的工具. 命令说明 as ...