Qt数据和视图分离——中MCV和MVVM
智能指针
- 一、背景知识
- 二、命令式编程 vs 声明式编程
- 2.1 命令式编程(Imperative Programming)
- 2.2 声明式编程(Declarative Programming)
- 三、 MVC(Model-View-Controller)
- 3.1 模型(Model)
- 3.2 视图(View)
- 3.3 控制器(Controller)
- 3.4 MVC 工作流程
- 3.5 总结
- 四、 MVVM(Model-View-ViewModel)
- 4.1 模型(Model)
- 4.2 视图(View)
- 4.3 视图模型(ViewModel)
- 4.5 MVVM 工作流程
- 4.6 总结
- 五、 MVC vs MVVM
- 5.1 MVC(模型-视图-控制器)
- 5.2 MVVM (模型-视图-视图模型)在Qt中的使用
- 5.3 区别总结
一、背景知识
回忆我们最初学Qt
的时候,经常通常都是在一个文件中,创建很多控件,然后在当前文件中处理该控件,包括信号槽的处理,控件的变化等等…我们最初用的就是所谓的命令式编程 也就是MVC
随着我们的项目愈发庞大,我们发现,我们的代码越来越难以维护,并且出现的bug
很难定位,俗称(屎山),后面我们了解到声明式编程 也就是MVVM
二、命令式编程 vs 声明式编程
2.1 命令式编程(Imperative Programming)
命令式编程是一种通过一系列指令和命令来改变程序状态的范式。开发者需要显式地描述如何进行某些操作,通常通过控制流(如条件语句、循环等),逐步指示计算机完成任务。这种方式强调“如何做”。
👁️👁️特点:
- 步骤驱动:开发者需要明确每个操作步骤。
- 状态管理:程序的状态在每一步变化中逐渐改变。
- 控制流:使用条件和循环来控制程序的执行顺序。
根据以下实例,我们通过信号和槽直接处理用户的点击事件,通过显式地调用方法来更新UI
。
#include <QApplication>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
#include <QWidget> int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget window; QVBoxLayout layout(&window); QLabel label("Hello, World!"); QPushButton button("Change Text"); layout.addWidget(&label); layout.addWidget(&button); // 命令式风格 QObject::connect(&button, &QPushButton::clicked, [&]() { label.setText("Text Changed!"); }); window.show(); return a.exec();
}
2.2 声明式编程(Declarative Programming)
声明式编程是一种通过声明或表达程序所需的结果而不是详细说明实现过程的范式。在这种方式中,开发者告诉计算机“做什么”,而不必去说明“怎么做”。这通常通过描述数据结构、约束条件或使用高级抽象来实现,降低了复杂度。
👁️👁️特点:
- 结果驱动:开发者关注于程序的目标,而不是实现细节。
- 数据抽象:数据和逻辑的分离,通常使用模型来管理数据。
- 更高的可维护性:由于代码更简洁,结构更清晰,通常更易于维护和扩展。
参考以下代码,数据的管理与视图的显示分开,模型负责处理数据,视图只关心如何展示,而不需关心背后的逻辑。
#include <QApplication>
#include <QListView>
#include <QStringListModel>
#include <QVBoxLayout>
#include <QWidget>
#include <QPushButton> class MyModel : public QStringListModel {
public: MyModel(QObject *parent = nullptr) : QStringListModel(parent) { setStringList({"Item 1", "Item 2", "Item 3"}); } void addItem(const QString &item) { QStringList items = stringList(); items.append(item); setStringList(items); }
}; int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget window; QVBoxLayout layout(&window); MyModel model; QListView view; view.setModel(&model); QPushButton button("Add Item"); QObject::connect(&button, &QPushButton::clicked, [&]() { model.addItem("New Item"); }); layout.addWidget(&view); layout.addWidget(&button); window.show(); return a.exec();
}
在Qt中,常见的数据和视图分离方式有使用Model-View-Controller (MVC)、Model-View-ViewModel (MVVM) 等设计模式。这些方法允许更清晰的分离数据逻辑和用户界面,从而提高代码的可维护性和可扩展性。
三、 MVC(Model-View-Controller)
MVC(Model-View-Controller)是一种软件架构模式,用于实现用户界面和应用程序之间的分离。这种模式帮助组织代码,提高了应用程序的可维护性和可扩展性。MVC 将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller)。
3.1 模型(Model)
模型负责处理应用程序的数据和业务逻辑。它直接与数据库交互,进行数据的存取和处理。在 MVC 模式中,模型独立于用户界面和控制逻辑,确保应用程序的数据状态保持一致。
👁️👁️功能:
- 管理应用程序的数据。
- 执行业务逻辑,包括数据验证和计算。
- 通知视图更新的数据状态(通常通过观察者模式)。
3.2 视图(View)
视图是用户界面部分,负责显示数据和呈现给用户。它从模型获取数据,并根据这些数据生成视觉输出。视图只是负责表现,不直接处理数据逻辑。
👁️👁️功能:
- 提供用户交互的界面。
- 显示模型中的数据。
- 监听用户输入,并将其转发给控制器。
3.3 控制器(Controller)
控制器是连接模型和视图的中介。它接收用户的输入,处理请求,并更新模型或视图。控制器会根据用户操作的类型选择相应的模型和视图进行处理。
👁️👁️功能:
- 接收用户输入和事件(如按钮点击)。
- 调用模型以获取或修改数据。
- 选择和更新适当的视图以呈现新的数据。
3.4 MVC 工作流程
- 用户与视图交互(例如,点击按钮)。
- 视图将用户的输入传递给控制器。
- 控制器处理输入,并可能请求模型更新(例如,保存用户修改的数据)。
- 模型更新后,会通知视图更新(通常通过观察者模式)。
- 视图接收到更新并重新渲染以显示新数据。
👁️👁️优点
- 分离关注点:每个组件的职责明确,代码更清晰。
- 可维护性高:分离使得修改任何一个部分对其他部分的影响减小。
- 可扩展性:容易添加新功能或修改现有功能;例如,可以独立于模型数据重构视图。
- 复用性:模型和视图可以在不同的应用程序中复用。
3.5 总结
MVC 是一种非常流行的设计模式,广泛用于Web应用程序和桌面应用程序开发。通过将用户界面与业务逻辑清晰分离,MVC 提供了一个灵活和高效的开发方式,有助于构建可维护和可扩展的应用程序。
MVVM(Model-View-ViewModel)是一种软件架构模式,主要用于构建用户界面,尤其在需要双向数据绑定的应用程序中非常常见。MVVM 模式通过分离关注点,提高了代码的可维护性和可测试性。它将应用程序分为三个主要组件:模型(Model)、视图(View)和视图模型(ViewModel)。
四、 MVVM(Model-View-ViewModel)
是一种软件架构模式,主要用于构建用户界面,尤其在需要双向数据绑定的应用程序中非常常见。MVVM 模式通过分离关注点,提高了代码的可维护性和可测试性。它将应用程序分为三个主要组件:模型(Model)、视图(View)和视图模型(ViewModel)。
4.1 模型(Model)
模型与 MVC 中的模型类似,负责处理应用程序的数据和业务逻辑。它可以是数据模型、数据存取层,或者业务逻辑代码。
👁️👁️功能:
- 表示应用程序的核心数据和业务逻辑。
- 直接与数据库和后端进行交互。
4.2 视图(View)
视图是用户界面部分,展示用户与应用程序交互的信息。视图通常包括按钮、文本框、图形等界面元素。
👁️👁️功能:
- 提供用户交互的界面。
- 直接绑定到视图模型,以反映数据的变化。
4.3 视图模型(ViewModel)
视图模型是连接视图和模型的中介,负责处理与视图的交互逻辑,并将数据提供给视图进行展示。视图模型使用数据绑定来更新视图,同时也提供处理用户输入和事件的逻辑。
👁️👁️功能:
- 提供视图所需的数据和命令。
- 通过属性通知视图更新(通常利用数据绑定机制)。
- 处理视图的状态和行为,与模型交互。
4.5 MVVM 工作流程
- 用户与视图交互(例如,点击按钮)。
- 视图通过数据绑定获得视图模型中的数据和命令。
- 视图模型接收到用户输入并更新模型或处理业务逻辑。
- 模型更新后,视图模型通过通知机制(如属性变化通知)更新视图。
- 视图更新以反映最新的数据。
👁️👁️优点:
- 双向数据绑定:提供更简洁的方式来连接UI和数据,自动更新。
- 可测试性高:视图模型包含了用户界面的具体逻辑,易于单元测试。
- 分离关注点:模型、视图和视图模型之间的分离使得代码结构清晰。
- 复用性:视图模型可以在不同视图间复用,不依赖于具体的UI实现。
4.6 总结
MVVM
模式特别适用于需要复杂用户交互和动态数据展示的场景,如桌面应用程序和Web应用程序,尤其是在使用现代前端框架(如 Angular、Vue、React 等)时。它通过将视图与逻辑分离,提高了代码的可维护性和可扩展性。
五、 MVC vs MVVM
在Qt
框架中,MVC
(模型-视图-控制器)和MVVM
(模型-视图-视图模型)也是常见的设计模式。虽然Qt
主要倾向于使用MVVM
,但二者之间仍然存在一些关键区别。下面详细介绍这两者在Qt中的应用和差异。
5.1 MVC(模型-视图-控制器)
👁️👁️结构:
- Model: 数据结构和业务逻辑,通常用
QAbstractItemModel
及其子类(如QStandardItemModel
)来实现。 - View: 界面元素,负责数据的展示。
Qt
提供了多种视图类(如QTableView、QListView
等)。 - Controller: 管理模型和视图之间的交互,但在
Qt
中,通常视图直接与模型交互,逻辑会嵌入在信号和槽中。
👁️👁️示例:
在一个简单的联系人管理应用中:
- Model: 使用QAbstractListModel来存储联系人信息。
- View: 使用QListView来展示联系人列表。
- Controller: 视图接收输入(例如,添加新联系人),然后更新模型,通常是通过信号和槽的机制。
5.2 MVVM (模型-视图-视图模型)在Qt中的使用
👁️👁️结构:
- Model: 同样负责数据和业务逻辑,使用QAbstractItemModel等实现。
- View: 界面部分,通常使用QML(Qt Modeling Language)或Qt Widgets。
- ViewModel: 负责将Model的数据转换为View所需的数据格式和行为。这可以通过QObject和Q_PROPERTY来实现,与数据绑定特性兼容。
👁️👁️示例:
在一个更复杂的任务管理应用中:
- Model: 使用QAbstractListModel实现任务数据。
- View: QML界面显示任务列表。
- ViewModel: 一个QObject子类,提供与UI组件绑定的属性,处理用户输入(如添加或删除任务)。
5.3 区别总结
-
数据绑定:
- MVC: 视图和模型之间的关系更加直接,通常需要手动更新视图。
- MVVM: 可以利用Qt的信号和槽机制,以及Q_PROPERTY,实现更简便的数据绑定。
-
解耦:
- MVC: 控制器和视图之间的关系较紧密,可能导致代码变得复杂。
- MVVM: 通过ViewModel实现较好的解耦,增强了代码的可测试性和可维护性。
-
适用场景:
- MVC: 更适合简单的桌面应用或较少交互的应用。
- MVVM: 适合更复杂、交互性较强的应用,尤其是使用QML的应用。
👁️👁️总结:
在Qt中,尽管MVC模式仍然适用,但MVVM因其更好的可维护性和可扩展性,尤其在使用QML时,更加广泛使用。选择哪种模式通常取决于项目的复杂性、需求以及团队的技术栈。
相关文章:
Qt数据和视图分离——中MCV和MVVM
智能指针 一、背景知识二、命令式编程 vs 声明式编程2.1 命令式编程(Imperative Programming)2.2 声明式编程(Declarative Programming) 三、 MVC(Model-View-Controller)3.1 模型(Model)3.2 视图ÿ…...
重定义变量类型:如#define FLOAT float和typedef float FLOAT的区别
在 C 或 C 中, #define 和 typedef 都可以用来为类型或值创建别名,但它们之间存在一些关键的区别: 预处理指令 ( #define ): #define 是预处理器指令,用于定义宏。 当编译器处理源代码时,预处理器会先运行&#…...

Qt 使用阿里矢量图标库
前言 阿里矢量图标库非常好用,里面有各种丰富的图标,完全免费,还支持自定义图标,还可以将图标打包到一个项目中,使用起来非常方便。 第一步: 打开阿里矢量图标库 第二步: 搜索图标&#x…...

仓颉语言运行时轻量化实践
杨勇勇 华为语言虚拟机实验室架构师,目前负责仓颉语言静态后端的开发工作 仓颉语言运行时轻量化实践 仓颉Native后端(CJNative)是仓颉语言的高性能、轻量化实现。这里的“轻量化”意指仓颉程序运行过程中占用系统资源(内存、CPU等…...
深入理解Python中的subprocess模块
目录 subprocess模块简介常用函数执行外部命令管道通信子进程管理错误处理实际应用示例最佳实践 subprocess模块简介 subprocess模块是Python标准库的一部分,提供了一个跨平台的方法来生成新进程、连接其输入/输出/错误管道,并获取其返回码。该模块旨…...

从零开始搭建 EMQX 集群压测框架
从零开始搭建 EMQX 集群压测框架 架构 在设计以EMQX为中心的MQTT消息队列集群压力测试框架时,我们采用微服务架构模式。EMQX作为消息队列的核心,负责处理MQTT协议的消息发布和订阅。Nginx作为EMQX的反向代理,负责负载均衡和SSL/TLS终端。MQT…...

ArkUI基本介绍
ArkUI:提供HarmonyOS应用UI开发框架,几件开发、精致体验、跨设备/跨平台。 ArkUI(方舟UI框架)为应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能(组件、布局、动画以及交互事件ÿ…...

vue2+OpenLayers 天地图上打点并且显示相关的信息(2)
上次是在地图上打点 这次鼠标移动在图标上面显示相关的信息 首先有两个事件 鼠标移入 和 鼠标移出事件 pointermove pointerout 鼠标放上去之前 放上去后 代码如下 <template><div class"container"><div id"vue-openlayers" class&quo…...

c++继承(二)
一、友元函数的继承 友元函数不能被继承,就像爸爸的朋友不是你的朋友,如果要有友元函数,在子类重新定义一个。 二、静态成员的继承 静态成员的继承仍然是那个成员,普通成员的继承是不同的。 父类的静态成员属于当前类…...

低代码开发的崛起:机遇与挑战
近年来,“低代码”开发平台的迅速崛起,已经成为IT行业中不可忽视的趋势。这些平台承诺让非专业人士也能快速构建应用程序,通过减少代码编写的需求,大幅提高开发效率。对于许多企业而言,低代码开发工具成为了一个加速数…...
Json-JacksonUtils工具类
为了创建一个通用的 Jackson 工具类,我们可以定义一个名为 JacksonUtils 的工具类,该类将提 供多种方法来支持不同类型的 JSON 转换需求。下面是一个示例实现,包括基本的 JSON 到 Java 对象的转换、Java 对象到 JSON 的转换、以及更复杂的类型如 CommonResult 的转换。 C…...
svn客户端装完后没有svn.exe
如果SVN客户端(如TortoiseSVN)安装完成后,在预期的安装目录(通常是bin目录)中没有找到svn.exe文件,这通常是因为在安装过程中没有选择安装命令行客户端工具(Command Line Client Toolsÿ…...

TinyWebserver的复现与改进(4):主线程的具体实现
GitHub - yzfzzz/MyWebServer: Linux高并发服务器项目,参考了TinyWebServer,将在此基础上进行性能改进与功能增加。为方便读者学习,附带详细注释和博客! TinyWebserver的复现与改进(1):服务器环…...
DaemonSet 不能帮助我们做什么事情?
DaemonSet 不能帮助我们做什么事情? A. 保证集群内每一个(或者一些)节点都运行一组相同的Pod B. 跟踪集群节点状态,保证新加入的节点自动创建对应的Pod C. 跟踪集群节点状态,保证移除的节点删除对应的Pod D. 能够设置Pod重试次数,…...
开源模型应用落地-LangChain高阶-记忆组件-RedisChatMessageHistory正确使用(八)
一、前言 LangChain 的记忆组件发挥着至关重要的作用,其旨在协助大语言模型(LLM)有效地留存历史对话信息。通过这一功能,使得大语言模型在对话过程中能够更出色地维持上下文的连贯性和一致性,进而能够像人类的记忆运作方式那样,进行更为自然、流畅且智能化的交互。 它仿佛…...

解决Openwrt 串口默认是没有密码的方法
将串口登录加入密码方法如下: 步骤一:配置busybox的登录,可以在.config文件中添加如下 CONFIG_BUSYBOX_CONFIG_LOGINy 添加后,需要重新编译busybox。 步骤二:修改target/linux/ramips/base-files/etc/inittab文件 将…...
【vue讲解:v-model 之 lazy、number、trim、与后端交互、小电影案例】
2 v-model 之 lazy、number、trim lazy:等待input框的数据绑定时区焦点之后再变化 number:数字开头,只保留数字,后面的字母不保留;字母开头,都保留 trim:去除首位的空格<!DOCTYPE html> …...

ECCV 2024 | 南洋理工三维数字人生成新范式:结构扩散模型
该论文作者均来自于新加坡南洋理工大学 S-Lab 团队,包括博士后胡涛,博士生洪方舟,以及计算与数据学院刘子纬教授(《麻省理工科技评论》亚太地区 35 岁以下创新者)。S-Lab 近年来在顶级会议如 CVPR, ICCV, ECCV, NeurIP…...

2024.8.13-算法学习(原创+转载)
一、什么是张量并行(Tensor Parallelism) ? 张量并行(Tensor Parallelism) 是一种分布式矩阵算法。 随着模型越来越大,模型内的矩阵也越来越大。一个大矩阵的乘法可以拆分成多个小矩阵的运算,…...

beautifulsoup的简单使用
文章目录 beautifulsoup一. beautifulsoup的简单使用1、安装2、如何使用3、对象的种类 二、beautifulsoup的遍历文档树2.1 子节点.contents 和 .children descendants2.2 节点内容.string.text 2.3 多个内容.strings**.stripped_strings** 2.4 父节点.parent.parents 三、beaut…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...