公司动态

QML与C++交互

📅 2026/8/18 18:45:39
QML与C++交互
QML 与 C++ 的交互是 Qt Quick 开发的核心需求,常用于将界面逻辑与底层业务逻辑解耦。一、基础交互机制元对象系统(Meta-Object System):基于 Qt 的 moc(元对象编译器)生成反射信息,实现 QML 与 C++ 的双向通信,依赖信号槽(Signals Slots)和属性绑定(Property Binding)‌。QML 引擎:通过 QQmlEngine 解析 QML 并建立与 C++ 的连接数据类型映射‌:QML 自动转换基础类型(如int、QString),复杂类型需注册为元类型(如QJsonObject)‌在 Qt 的 QML/C++ 集成中,qmlRegisterType和setContextProperty是两种将 C++ 对象暴露给 QML 的主要方式,它们有显著的不同和使用场景。区别对比特性qmlRegisterTypesetContextProperty用途注册类型,允许在 QML 中创建新实例暴露特定对象实例到 QML 上下文对象生命周期由 QML 引擎管理由 C++ 控制QML 中的使用方式可以创建多个实例 (Person {})直接访问固定实例 (globalPerson)典型应用场景可复用的组件类全局单例、应用配置等版本控制支持 (通过 uri 和版本号)不支持线程安全性自动处理需要手动确保线程安全二、C++ 暴露给 QML1. 注册上下文属性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 qmlRegisterTypePerson("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_INVOKABLEcppclass 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; QHashint, QByteArray roleNames() const override; //设置数据 Q_INVOKABLE void updateData(QListLeakInputFileInfo inputData); //获取数量 Q_INVOKABLE int getHistoryFileCount(); Q_INVOKABLE void setSelected(int row, bool selected); Q_INVOKABLE bool isSelected(int row); protected: QListLeakInputFileInfo 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(); } } QHashint, QByteArray HistoryModel::roleNames() const { return { {NameRole, "name"}, {FileSizeRole, "fileSize"}, {FilePathRole, "filePath"}, {TypeRole, "type"}, {LastModifyDatetimeRole, "lastModifyDatetime"}, {selectedRole, "selected"}, {keyNameRole, "keyName"} }; } //设置数据 void HistoryModel::updateData(QListLeakInputFileInfo 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; //qRegisterMetaTypeHistoryModel*("HistoryModel*"); MyObject myObject; // 设置上下文属性 engine.rootContext()-setContextProperty("MO_Object", myObject);