news 2026/8/18 18:44:58

QML与C++交互

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QML与C++交互

QML 与 C++ 的交互是 Qt Quick 开发的核心需求,常用于将界面逻辑与底层业务逻辑解耦。

一、基础交互机制

  • 元对象系统(Meta-Object System):基于 Qt 的 moc(元对象编译器)生成反射信息,实现 QML 与 C++ 的双向通信,依赖信号槽(Signals & Slots)和属性绑定(Property Binding)‌。

  • QML 引擎:通过 QQmlEngine 解析 QML 并建立与 C++ 的连接

  • 数据类型映射‌:QML 自动转换基础类型(如 intQString),复杂类型需注册为元类型(如 QJsonObject)‌

在 Qt 的 QML/C++ 集成中,qmlRegisterType 和 setContextProperty 是两种将 C++ 对象暴露给 QML 的主要方式,它们有显著的不同和使用场景。

区别对比

特性qmlRegisterTypesetContextProperty
用途注册类型,允许在 QML 中创建新实例暴露特定对象实例到 QML 上下文
对象生命周期由 QML 引擎管理由 C++ 控制
QML 中的使用方式可以创建多个实例 (Person {})直接访问固定实例 (globalPerson)
典型应用场景可复用的组件类全局单例、应用配置等
版本控制支持 (通过 uri 和版本号)不支持
线程安全性自动处理需要手动确保线程安全

二、C++ 暴露给 QML

1. 注册上下文属性

cpp

// main.cpp QQmlApplicationEngine engine; QString hello = "World"; // 设置上下文属性 engine.rootContext()->setContextProperty("helloText", hello); // QML 中直接使用 // Text { text: helloText }

2. 注册 C++ 类型

cpp

// person.h class Person : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) public: // ... 属性和方法实现 }; // main.cpp qmlRegisterType<Person>("People", 1, 0, "Person"); // QML 中使用 // import People 1.0 // Person { name: "Alice" }

Q_PROPERTY 是 Qt 中连接 C++ 后端与 QML 前端的关键机制,它允许将 C++ 类的成员变量作为属性暴露给 QML 使用。

Q_PROPERTY(type name READ getFunction [WRITE setFunction] [NOTIFY signal] [OTHER_OPTIONS])

3. 使用 Q_INVOKABLE

cpp

class Calculator : public QObject { Q_OBJECT public: Q_INVOKABLE int add(int a, int b) { return a + b; } }; // QML 中调用 // calculator.add(2, 3)

Q_INVOKABLE 是 Qt 提供的一个宏,用于标记 C++ 成员函数可以从 QML 或 Qt 的元对象系统(如信号槽)中调用。
public slots函数也可以从 QML 中调用。
核心区别

特性Q_INVOKABLEpublic slots
调用方式直接函数调用信号槽机制或直接调用
性能略高(直接调用)略低(经过元对象系统)
使用场景任何需要暴露给QML的函数主要用于信号连接
信号连接不能作为槽接收信号可以作为槽接收信号
返回值支持支持
参数类型必须是QVariant支持的类型必须是QVariant支持的类型

示例:

#include <QObject> class MyClass : public QObject { Q_OBJECT public: // 普通成员函数 - QML 不可见 void normalFunction(); // QML 可调用的函数 Q_INVOKABLE void invokableFunction(); // 带返回值的可调用函数 Q_INVOKABLE QString getInfo(); // 带参数的可调用函数 Q_INVOKABLE void setValue(int value); };

4. 暴露一个对象(包含了多个成员类)

使用Q_PROPERTY定义类变量,这个需要使用指针变量。

#MyObject.h #HistoryModel一个模型自定义类 struct LeakInputFileInfo { QString name; long long fileSize; QString filePath; int type; QString lastModifyDatetime; QString keyName; bool selected; }; // 注册元类型 Q_DECLARE_METATYPE(LeakInputFileInfo) class HistoryModel: public QAbstractListModel { Q_OBJECT public: enum Roles { NameRole = Qt::UserRole + 1, FileSizeRole, FilePathRole, TypeRole, LastModifyDatetimeRole, selectedRole, keyNameRole }; explicit HistoryModel(QObject *parent = nullptr); //需要实现的方法 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; //设置数据 Q_INVOKABLE void updateData(QList<LeakInputFileInfo> inputData); //获取数量 Q_INVOKABLE int getHistoryFileCount(); Q_INVOKABLE void setSelected(int row, bool selected); Q_INVOKABLE bool isSelected(int row); protected: QList<LeakInputFileInfo> m_data; } //HistoryModel是类定义,自己去实现。 int HistoryModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return parent.isValid() ? 0 : m_data.size(); } QVariant HistoryModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_data.size()) return QVariant(); const auto &item = m_data.at(index.row()); switch (role) { case NameRole: return item.name; case FileSizeRole: return item.fileSize; case FilePathRole: return item.filePath; case TypeRole: return item.type; case LastModifyDatetimeRole: return item.lastModifyDatetime; case selectedRole: return item.selected; case keyNameRole: return item.keyName; default: return QVariant(); } } QHash<int, QByteArray> HistoryModel::roleNames() const { return { {NameRole, "name"}, {FileSizeRole, "fileSize"}, {FilePathRole, "filePath"}, {TypeRole, "type"}, {LastModifyDatetimeRole, "lastModifyDatetime"}, {selectedRole, "selected"}, {keyNameRole, "keyName"} }; } //设置数据 void HistoryModel::updateData(QList<LeakInputFileInfo> inputData) { beginResetModel(); m_data = inputData; endResetModel(); } int HistoryModel::getHistoryFileCount() { return m_data.size(); } void HistoryModel::setSelected(int row, bool selected) { if (row < 0 || row >= m_data.size()) return; if (m_data[row].selected == selected) return; // 状态未变,无需更新 m_data[row].selected = selected; // 通知视图该行数据已更改(只刷新 selected 角色) QModelIndex idx = index(row); emit dataChanged(idx, idx, { selectedRole }); } bool HistoryModel::isSelected(int row) { if (row < 0 || row >= m_data.size()) return false; return m_data[row].selected; } #MyObject class MyObject: public QObject { Q_OBJECT Q_PROPERTY(HistoryModel* historyModel READ historyModel CONSTANT) Q_PROPERTY(QStringListModel* newModel READ newModel CONSTANT) public: explicit MyObject(QObject *parent = nullptr); HistoryModel* historyModel() const; QStringListModel * newModel() const; Q_INVOKABLE int getFileCount(); public: HistoryModel* m_historyModel; QStringListModel * m_newModel; } #MyObject.cpp MyObject::MyObject(QObject *parent) : QObject{parent} { m_historyModel = new HistoryModel(); m_newModel = new QStringListModel(); } MyObject* MyObject::historyModel() const { return m_historyModel ; } MyObject* MyObject::newModel() const { return m_newModel; } int MyObject::getFileCount() { return 100; }

 注册

// main.cpp QQmlApplicationEngine engine; //qRegisterMetaType<HistoryModel*>("HistoryModel*"); MyObject myObject; // 设置上下文属性 engine.rootContext()->setContextProperty("MO_Object", myObject);
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/18 18:39:52

计算机毕业设计之公寓之家小程序

当前&#xff0c;由于人们生活水平的提高和思想观念的改变&#xff0c;然后随着经济全球化的背景之下&#xff0c;互联网技术将进一步提高社会综合发展的效率和速度&#xff0c;互联网技术也会涉及到各个领域&#xff0c;于是传统的管理方式对时间、地点的限制太多&#xff0c;…

作者头像 李华
网站建设 2026/8/18 18:39:49

计算机毕业设计之公园管理系统

近年来&#xff0c;科技飞速发展&#xff0c;在经济全球化的背景之下&#xff0c;互联网技术将进一步提高社会综合发展的效率和速度&#xff0c;互联网技术也会涉及到各个领域&#xff0c;而公园管理系统在网络背景下有着无法忽视的作用。信息管理系统的开发是一个不断优化的过…

作者头像 李华
网站建设 2026/8/18 18:39:04

GLYKEN可莱康二十年产业积累,探索燕窝肽健康产业新未来

近年来&#xff0c;随着消费者对健康意识的日益提高&#xff0c;大健康产业正在迎来一次重要的转型&#xff0c;正从传统滋补迈向科学营养和日常管理的新阶段。在这样的背景下&#xff0c;GLYKEN&#xff08;可莱康&#xff09;在燕窝肽领域全力以赴&#xff0c;借助科技创新为…

作者头像 李华