news 2025/12/19 14:37:42

QML中关联C++ Model 类的两种核心方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QML中关联C++ Model 类的两种核心方式

QML 中关联 C++ Model 类的两种核心方式:import 和 setContextProperty。

这两种方式的本质区别在于 Model 的提供者和作用域。

方式一:注册为 QML 类型并 Import 使用

这种方式是将 C++ 类注册到 QML 类型系统中,使其在 QML 中像一个内置类型一样被使用。

实现步骤:

  1. 在 C++ 中注册类型:使用 qmlRegisterType 函数将你的 Model 类注册为一个可在 QML 中实例化的类型。
  2. 在 QML 中 Import:在使用该 Model 的 QML 文件中,通过 import 语句导入其所在的模块。
  3. 在 QML 中声明实例化:像使用 Rectangle、Text 等元素一样,直接使用注册的类名来创建对象。

代码示例:

C++ 部分 (main.cpp 或某个初始化文件)

#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> // 假设你的 Model 类头文件 #include "mystringlistmodel.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; // 关键步骤:将 MyStringListModel 注册为 QML 类型 // 参数:<模块名(如MyApp)>、<主版本号>、<次版本号>、<QML中的类型名> qmlRegisterType<MyStringListModel>("MyModels", 1, 0, "MyStringListModel"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }

C++ Model 类 (mystringlistmodel.h/cpp)
这里以一个简单的字符串列表模型为例。

// mystringlistmodel.h #ifndef MYSTRINGLISTMODEL_H #define MYSTRINGLISTMODEL_H #include <QAbstractListModel> #include <QStringList> class MyStringListModel : public QAbstractListModel { Q_OBJECT public: explicit MyStringListModel(QObject *parent = nullptr); // 必须重写的函数 int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; // 可选:如果需要可编辑,重写此函数 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex &index) const override; // 自定义角色 enum Roles { NameRole = Qt::UserRole + 1, ColorRole }; Q_ENUM(Roles) // 将枚举暴露给 QML // 添加数据的方法 public slots: void addItem(const QString &name, const QString &color); private: QStringList m_names; QStringList m_colors; }; #endif // MYSTRINGLISTMODEL_H

(.cpp 文件实现略,重点是展示如何在 QML 中使用)

QML 部分 (main.qml)

import QtQuick 2.15 import QtQuick.Controls 2.15 import MyModels 1.0 // 导入我们注册的模块 ApplicationWindow { width: 400 height: 300 visible: true // 直接在 QML 中声明并实例化我们的 Model // 就像使用一个普通的 QML Item 一样 MyStringListModel { id: stringModel // 可以在这里直接调用其槽函数来初始化数据 Component.onCompleted: { addItem("Apple", "red") addItem("Banana", "yellow") addItem("Grape", "purple") } } ListView { anchors.fill: parent model: stringModel // 将 ListView 的 model 设置为这个实例 delegate: Rectangle { width: ListView.view.width height: 40 color: model.color // 使用我们在 C++ 中定义的 ColorRole Text { text: model.name // 使用 NameRole anchors.centerIn: parent } } } }

特点与适用场景:

• 特点:

◦ 模块化:Model 成为 QML 环境的一部分,可以被任何导入相应模块的 QML 文件使用。 ◦ 封装性好:Model 的创建和配置逻辑可以完全放在 QML 端。 ◦ 可复用性高:同一个 Model 类可以在多个地方被实例化。 ◦ 类型安全:在编译时就能检查类型错误(如果工具支持)。

• 适用场景:

◦ 通用的、可复用的 Model 组件。 ◦ 希望将 Model 的创建和生命周期管理完全交给 QML 的场景。 ◦ 构建大型的、模块化的 QML 应用程序。

方式二:使用 setContextProperty

这种方式是在 C++ 端将一个已经创建好的 QObject 派生类(包括 Model)实例设置为 QML 引擎的上下文属性,使其在整个 QML 上下文中可用。

实现步骤:

  1. 在 C++ 中创建实例:在 C++ 代码中(通常是 main 函数中),创建你的 Model 类的实例。
  2. 设置上下文属性:使用 QQmlEngine::rootContext()->setContextProperty() 将这个实例注册为一个全局可用的 QML 对象。
  3. 在 QML 中直接使用:在 QML 中,可以直接使用你设置的名称来访问这个对象,无需 import。

代码示例:

C++ 部分 (main.cpp) #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "mystringlistmodel.h" // 同样的 Model 类 int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; // 1. 在 C++ 端创建 Model 实例 MyStringListModel stringModel; // 可以添加一些初始数据 // stringModel.addItem(...); // 2. 关键步骤:将实例设置为上下文属性 // 参数:<在QML中使用的名称>, <C++对象的指针> engine.rootContext()->setContextProperty("myCppModel", &stringModel); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }

QML 部分 (main.qml)

import QtQuick 2.15 import QtQuick.Controls 2.15 // 注意:这里没有 ‘import MyModels 1.0’ ApplicationWindow { width: 400 height: 300 visible: true // 注意:没有在 QML 中声明 MyStringListModel // 它已经在 C++ 中被创建好了 ListView { anchors.fill: parent // 3. 直接使用在 C++ 中设置的上下文属性名 ‘myCppModel’ model: myCppModel delegate: Rectangle { width: ListView.view.width height: 40 color: model.color Text { text: model.name anchors.centerIn: parent } } } // 甚至可以在 Button 的 onClicked 中直接调用 C++ Model 的方法 Button { text: "Add Item" anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter onClicked: { // 直接调用 C++ 对象的槽函数 myCppModel.addItem("New Fruit", "green") } } }

特点与适用场景:

• 特点:

◦ 简单直接:对于单个实例或单例模式的 Model 非常方便。 ◦ 控制权在 C++:Model 的生命周期由 C++ 控制,通常在整个应用运行期间都存在。 ◦ 全局可用:一旦设置,在所有导入了该上下文的 QML 文件中都可以访问。 ◦ 无需注册类型:不需要使用 qmlRegisterType,代码稍简洁一些。

• 适用场景:

◦ 应用程序的全局状态管理(如用户数据、配置信息)。 ◦ 单例服务或管理器类。 ◦ 需要与 C++ 深度交互、且只有一个实例的 Model。 ◦ 快速原型开发或小型项目。

对比总结

特性 注册类型 (qmlRegisterType) 设置上下文属性 (setContextProperty)

提供者 QML 引擎的类型系统 QML 引擎的根上下文

使用方式 import + 声明式实例化 直接使用属性名

生命周期 QML 垃圾回收机制管理 C++ 端管理(通常是长期存在)

作用域 模块内可见 整个 QML 上下文可见(全局)

复用性 高,可创建多个实例 低,通常只有一个实例

灵活性 高,可在 QML 中任意创建和配置 较低,实例化和配置主要在 C++

典型用例 可复用的 UI 组件、通用 Model 全局状态、单例服务、管理器

如何选择?

• 如果你的 Model 是数据驱动的、需要被多个视图复用、或者其行为和创建逻辑更适合在 QML 中描述,请选择 注册类型。

• 如果你的 Model 代表一个全局的、单一的应用程序状态或服务,并且其生命周期应该由 C++ 牢牢掌控,请选择 设置上下文属性。

在实际项目中,这两种方式常常结合使用。例如,使用上下文属性提供一个全局的配置 Model,同时使用注册类型为不同的列表页面提供特定的数据 Model。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/19 14:36:50

在Blazor项目里构造一个覆盖面广泛的权限组件

前言 之前笔者写过一篇推广Blazor的博客《安利一下Blazor&#xff1a;.NET开发者的全栈“优”选项》&#xff0c;简单的聊过一点Blazor的话题&#xff0c;以及它和一些前端框架&#xff08;如Vue&#xff0c;React&#xff09;的异曲同工之处。 近期在开发的一个基于Blazor S…

作者头像 李华
网站建设 2025/12/19 14:34:24

FaceFusion人脸替换可用于文化遗产活化再现

FaceFusion人脸替换可用于文化遗产活化再现 在敦煌莫高窟的一幅唐代壁画前&#xff0c;一位游客举起手机扫描二维码——刹那间&#xff0c;画中身着华服的供养人缓缓转头&#xff0c;微笑着开口讲述千年前开凿石窟的故事。这不是科幻电影场景&#xff0c;而是借助AI技术正在实现…

作者头像 李华
网站建设 2025/12/19 14:33:38

出售前如何擦除iPhone数据?9个技巧与3种简单解决方案

iPhone的使用寿命很长&#xff0c;如果保养得当&#xff0c;通常可达10年。但由于苹果频繁更新设备&#xff0c;大多数用户每3年就会通过出售旧设备来升级。然而&#xff0c;在出售之前&#xff0c;采取一些步骤以避免潜在问题是非常重要的。本文将介绍如何在出售前擦除iPhone数…

作者头像 李华
网站建设 2025/12/19 14:33:04

收藏!35岁程序员转型大模型全攻略:凭技术积淀破局,平稳衔接新赛道

35岁&#xff0c;是程序员职业道路上的一道“分水岭”——传统开发岗位的年龄限制、重复劳动的职业倦怠、技术迭代的焦虑感&#xff0c;让不少人陷入“转型无门、坚守乏力”的困境。而大模型浪潮的席卷&#xff0c;恰好为有多年技术积淀的程序员打开了新天窗&#xff1a;你的编…

作者头像 李华
网站建设 2025/12/19 14:28:45

【Python新手村】字典(Dict):别再大海捞针,我有专属“标签”!

哈喽&#xff0c;各位 Python 练习生&#xff01;在前面的旅程里&#xff0c;我们见识过了列表、元组和集合。今天我们要聊的这位&#xff0c;是 Python 里的“情报局局长”——字典 (Dictionary)。想象一下&#xff0c;如果你在列表里存了 1000 个人的信息&#xff0c;想找“张…

作者头像 李华
网站建设 2025/12/19 14:28:31

【技术教程】Node.js 包管理工具全面对比:npm、npx、pnpm 与 cnpm

Node.js 包管理工具全面对比&#xff1a;npm、npx、pnpm 与 cnpm 以下是对 Node.js 生态中常用包管理工具 npm、npx、pnpm 和 cnpm 的全面对比分析&#xff08;基于 2025 年现状&#xff09;。内容涵盖定义、核心理念、使用场景、优劣势对比以及具体使用示例。 1. 定义npm&…

作者头像 李华