当前位置: 首页 > news >正文

Qt 应用开发之 MVC 架构

在Qt应用开发中,MVC(Model-View-Controller)架构确实是一种常用的设计模式,它通过将应用程序的业务逻辑、数据展示和用户交互分离开来,显著提高了代码的可维护性和可扩展性。以下是MVC架构在Qt应用开发中的原理阐述:

一、MVC架构的基本概念

MVC架构起源于Smalltalk,是Model(模型)、View(视图)和Controller(控制器)的缩写。在Qt应用开发中,MVC架构的具体含义如下:

  1. Model(模型):是应用程序的数据模型部分,负责管理应用程序的数据,提供对数据的增删改查等操作。它是应用程序的核心部分,并与数据源进行通信,为架构中的其他组件(如视图和委托)提供了接口。
  2. View(视图):是应用程序的可视化部分,负责展示数据,将Model维护的数据进行可视化呈现,并提供用户操作界面。它依据模型数据创建,并从模型中获得模型索引(Model Index),该索引用来表示数据项。
  3. Controller(控制器):是应用程序的控制器部分,负责接收和处理View层的用户操作并作出响应,同时还管理Model和View之间的通讯。它是Model和View之间的桥梁。

二、MVC架构在Qt中的实现原理

在Qt中,MVC架构的实现原理主要依赖于模型/视图架构(Model/View Architecture)以及委托(Delegate)的概念。

  1. 模型/视图架构

    • 将数据的存储和数据向用户的展示进行了分离,提供了更为简单的框架。
    • 数据和界面进行分离,使得相同的数据可以在多个不同的视图中显示,而且还可以创建新的视图,而不需要改变底层的数据框架。
  2. 委托(Delegate)

    • 为了对用户输入进行灵活处理,Qt引入了委托(也被称为代理Delegate)的概念。
    • 委托可以定制数据的渲染和编辑方式。在标准的视图中,委托负责渲染数据项;当编辑项目时,委托使用模型索引直接与模型进行通信。

三、MVC架构在Qt中的优势

  1. 分离关注点:MVC模式将数据、用户界面和业务逻辑分离开来,使得代码更易于理解和维护。
  2. 可扩展性:由于模块之间的松耦合性,可以更容易地添加新的功能或修改现有功能。
  3. 可重用性:通过将数据和界面分离,可以更容易地重用模型和视图组件。
  4. 可测试性:由于模块之间的明确分离,可以更容易地对模型、视图和控制器进行单元测试。

四、MVC架构在Qt中的实际应用

在Qt中,MVC架构被广泛应用于各种应用程序的开发中。例如,在一个计算器应用程序中:

  • Model部分维护了所有操作数和运算符的状态,提供了计算功能。
  • View部分提供了用户界面,包括输入框、显示框、按钮等,将Model运算结果可视化呈现。
  • Controller部分负责处理用户操作,包括点击按钮、输入数据等操作,并将其传送给Model进行处理。

五、应用示例

以下是一个简单的示例,包括模型(Model)、视图(View)和控制器(Controller)的实现,以及相应的 CMakeLists.txt 文件来组织项目。

项目结构
CalculatorApp/
├── CMakeLists.txt
├── include/
│   ├── controller.h
│   ├── model.h
│   └── view.h
├── main.cpp
├── src/
│   ├── controller.cpp
│   ├── mainwindow.cpp
│   ├── mainwindow.h
│   ├── mainwindow.ui
│   ├── model.cpp
│   └── view.cpp
└── resources/└── icons/
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)project(CalculatorApp VERSION 1.0 LANGUAGES CXX)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# Find the required Qt modules
find_package(Qt5 COMPONENTS Widgets REQUIRED)# Include directories
include_directories(${CMAKE_SOURCE_DIR}/include)# Add the executable
add_executable(CalculatorAppmain.cppsrc/mainwindow.cppsrc/controller.cppsrc/model.cppsrc/view.cpp
)# Link the Qt libraries
target_link_libraries(CalculatorApp Qt5::Widgets)# Add UI and resource files
set_source_files_properties(src/mainwindow.ui PROPERTIES HEADER_FILE_ONLY ON)
qt5_add_resources(RESOURCES ${CMAKE_SOURCE_DIR}/resources/resources.qrc)
Model (model.h)
#ifndef MODEL_H
#define MODEL_H#include <QObject>class Model : public QObject
{Q_OBJECTpublic:explicit Model(QObject *parent = nullptr);double add(double a, double b);double subtract(double a, double b);double multiply(double a, double b);double divide(double a, double b);signals:public slots:
};#endif // MODEL_H
Model (model.cpp)
#include "model.h"Model::Model(QObject *parent) : QObject(parent)
{
}double Model::add(double a, double b)
{return a + b;
}double Model::subtract(double a, double b)
{return a - b;
}double Model::multiply(double a, double b)
{return a * b;
}double Model::divide(double a, double b)
{if (b != 0)return a / b;return 0; // Avoid division by zero
}
View (view.h)
#ifndef VIEW_H
#define VIEW_H#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>class View : public QWidget
{Q_OBJECTpublic:explicit View(QWidget *parent = nullptr);void setResult(double result);signals:void number1Changed(double value);void number2Changed(double value);void operationSelected(int index);private slots:void onNumber1Changed(const QString &text);void onNumber2Changed(const QString &text);private:QLineEdit *number1Edit;QLineEdit *number2Edit;QLabel *resultLabel;QPushButton *addButton;QPushButton *subtractButton;QPushButton *multiplyButton;QPushButton *divideButton;
};#endif // VIEW_H
View (view.cpp)
#include "view.h"
#include <QDoubleValidator>View::View(QWidget *parent) : QWidget(parent)
{QVBoxLayout *layout = new QVBoxLayout(this);number1Edit = new QLineEdit(this);number2Edit = new QLineEdit(this);resultLabel = new QLabel(this);addButton = new QPushButton("Add", this);subtractButton = new QPushButton("Subtract", this);multiplyButton = new QPushButton("Multiply", this);divideButton = new QPushButton("Divide", this);QDoubleValidator *validator = new QDoubleValidator(this);number1Edit->setValidator(validator);number2Edit->setValidator(validator);connect(number1Edit, &QLineEdit::textChanged, this, &View::onNumber1Changed);connect(number2Edit, &QLineEdit::textChanged, this, &View::onNumber2Changed);connect(addButton, &QPushButton::clicked, this, [this]() { emit operationSelected(0); });connect(subtractButton, &QPushButton::clicked, this, [this]() { emit operationSelected(1); });connect(multiplyButton, &QPushButton::clicked, this, [this]() { emit operationSelected(2); });connect(divideButton, &QPushButton::clicked, this, [this]() { emit operationSelected(3); });layout->addWidget(number1Edit);layout->addWidget(number2Edit);layout->addWidget(resultLabel);layout->addWidget(addButton);layout->addWidget(subtractButton);layout->addWidget(multiplyButton);layout->addWidget(divideButton);setLayout(layout);
}void View::setResult(double result)
{resultLabel->setText(QString::number(result));
}void View::onNumber1Changed(const QString &text)
{bool ok;double value = text.toDouble(&ok);if (ok)emit number1Changed(value);
}void View::onNumber2Changed(const QString &text)
{bool ok;double value = text.toDouble(&ok);if (ok)emit number2Changed(value);
}
Controller (controller.h)
#ifndef CONTROLLER_H
#define CONTROLLER_H#include <QObject>
#include "model.h"
#include "view.h"class Controller : public QObject
{Q_OBJECTpublic:Controller(Model *model, View *view, QObject *parent = nullptr);private slots:void handleNumber1Changed(double value);void handleNumber2Changed(double value);void handleOperationSelected(int index);private:Model *model;View *view;
};#endif // CONTROLLER_H
Controller (controller.cpp)
#include "controller.h"Controller::Controller(Model *model, View *view, QObject *parent): QObject(parent), model(model), view(view)
{connect(view, &View::number1Changed, this, &Controller::handleNumber1Changed);connect(view, &View::number2Changed, this, &Controller::handleNumber2Changed);connect(view, &View::operationSelected, this, &Controller::handleOperationSelected);
}void Controller::handleNumber1Changed(double value)
{// Handle number1 change if needed
}void Controller::handleNumber2Changed(double value)
{// Handle number2 change if needed
}void Controller::handleOperationSelected(int index)
{double num1 = view->findChild<QLineEdit*>("number1Edit")->text().toDouble();double num2 = view->findChild<QLineEdit*>("number2Edit")->text().toDouble();double result = 0;switch (index) {case 0:result = model->add(num1, num2);break;case 1:result = model->subtract(num1, num2);break;case 2:result = model->multiply(num1, num2);break;case 3:result = model->divide(num1, num2);break;}view->setResult(result);
}
MainWindow (mainwindow.h)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "controller.h"
#include "model.h"
#include "view.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:// 这里可以添加槽函数,用于处理信号和槽机制// 例如:void onSomeButtonClicked();private:Ui::MainWindow *ui;Model *model;    // 指向模型对象的指针View *view;      // 指向视图对象的指针Controller *controller; // 指向控制器对象的指针// 初始化函数,用于设置 UI、模型、视图和控制器void initialize();// 其他私有成员函数// 例如:void setupUi();//       void setupModel();//       void setupView();//       void setupController();
};#endif // MAINWINDOW_H
MainWindow (mainwindow.cpp)
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow),model(new Model(this)),view(new View(this)),controller(new Controller(model, view, this))
{ui->setupUi(this);initialize();
}MainWindow::~MainWindow()
{delete ui;delete model;delete view;delete controller;
}void MainWindow::initialize()
{// 在这里进行初始化,例如:// setupUi();// setupModel();// setupView();// setupController();// 设置视图和控制器之间的连接等// 例如:connect(someSignal, this, &MainWindow::someSlot);
}// 其他成员函数的具体实现

相关文章:

Qt 应用开发之 MVC 架构

在Qt应用开发中&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;架构确实是一种常用的设计模式&#xff0c;它通过将应用程序的业务逻辑、数据展示和用户交互分离开来&#xff0c;显著提高了代码的可维护性和可扩展性。以下是MVC架构在Qt应用开发中的原理阐述&am…...

python之字符串总结

字符串&#xff08;str&#xff09; 对于字符串的学习&#xff0c;我整理了网上的一些资料&#xff0c;希望可以帮助到各位&#xff01;&#xff01;&#xff01; 概述 由多个字母&#xff0c;数字&#xff0c;特殊字符组成的有限序列 字符串的定义&#xff1a;可以使用一对…...

Flutter鸿蒙next 封装 Dio 网络请求详解:登录身份验证与免登录缓存

✅近期推荐&#xff1a;求职神器 https://bbs.csdn.net/topics/619384540 &#x1f525;欢迎大家订阅系列专栏&#xff1a;flutter_鸿蒙next &#x1f4ac;淼学派语录&#xff1a;只有不断的否认自己和肯定自己&#xff0c;才能走出弯曲不平的泥泞路&#xff0c;因为平坦的大路…...

sql server复制一张表(表结构或表数据)SQL语句整理

1. 复制表结构及数据到新表 CREATE TABLE 新表 SELECT * FROM 旧表;这种方法会复制 旧表 中的所有内容到 新表&#xff0c;但新表不会保留原表的主键、自动递增等属性。为了保持这些属性&#xff0c;需要使用 ALTER 语句进行后续处理 2. 只复制表结构到新表 使用条件始终为假…...

c语言-进位计数制

文章目录 一、进位计数制是什么&#xff1f;二、c语言1.二进制转十进制2.十进制转二进制 一、进位计数制是什么&#xff1f; 进位计数制简称进制&#xff0c;是人类用于计算数量的基本规则。 可使用数字符号的数目称为基数或底数&#xff0c;基数个数为n个&#xff0c;即可称n…...

记本地第一次运行seatunnel示例项目

前置 静态源码编译通过&#xff1a;https://blog.csdn.net/u011924665/article/details/143372464 参考 seatunnel官方的开发环境搭建文档&#xff1a;https://seatunnel.incubator.apache.org/zh-CN/docs/2.3.5/contribution/setup 安装scala 下载scala 去官网下载&…...

Threejs 实现 VR 看房完结

效果&#xff1a; threejs 3d Vr 看房 gitee 地址&#xff1a; threejs-3d-map: 1、threejs 实现3d 地图效果链接&#xff1a;https://blog.csdn.net/qq_57952018/article/details/1430539902、threejs 实现 vr 看房 主要代码&#xff1a; src/views/PanoramicView/index.vu…...

找出目标值在数组中的开始和结束位置(二分查找)

给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 示例 1&#xff1a…...

VSCode进阶之路

VSCode进阶之路&#xff1a;从入门到高效率开发 &#x1f680; Hey&#xff0c;朋友们好&#xff01;还在为VSCode的海量功能感到眼花缭乱吗&#xff1f;咱们一起来解锁VSCode的超神技能吧&#xff01; 开篇碎碎念 &#x1f3af; 第一次用VSCode时&#xff0c;就像个闯入魔法世…...

leetcode-21-合并两个有序链表

题解&#xff1a; 1、初始化哑节点dum 2、 3、 代码&#xff1a; 参考&#xff1a;leetcode-88-合并两个有序数组...

SSM项目部署到服务器

将SSM&#xff08;Spring Spring MVC MyBatis&#xff09;项目部署到服务器上&#xff0c;通常需要以下步骤&#xff1a; 打包项目 生成一个WAR文件&#xff0c;通常位于target目录下 配置Tomcat&#xff1a; 将生成的WAR文件复制到Tomcat的webapps目录下。 配置conf/se…...

【Linux】网络编程:初识协议,序列化与反序列化——基于json串实现,网络通信计算器中简单协议的实现、手写序列化与反序列化

目录 一、什么是协议&#xff1f; 二、为什么需要有协议呢&#xff1f; 三、协议的应用 四、序列化与反序列化的引入 什么是序列化和反序列化&#xff1f; 为什么需要序列化和反序列化&#xff1f; 五、序列化推荐格式之一&#xff1a;JSON介绍 六、网络版计算器编程逻…...

Educational Codeforces Round 171 (Rated for Div. 2)(A~D) 题解

Problem - A - Codeforces--PerpendicularSegments 思路:正方形对角线最长,并且相互垂直.直接输出即可. int x,y,k; void solve(){ //Acin>>x>>y>>k;int resmin(x,y);cout<<"0 0"<<" "<<res<<" &q…...

【教程】Git 标准工作流

目录 前言建仓&#xff0c;拉仓&#xff0c;关联仓库修改代码更新本地仓库&#xff0c;并解决冲突提交代码&#xff0c;合入代码其他常用 Git 工作流删除本地仓库和远程仓库中的文件日志打印commit 相关 前言 Git 是日常开发中常用的版本控制工具&#xff0c;配合代码托管仓库…...

Nico,从零开始干掉Appium,移动端自动化测试框架实现

开头先让我碎碎念一波~去年差不多时间发布了一篇《 UiAutomator Nico&#xff0c;一个基于纯 adb 命令实现的安卓自动化测试框》&#xff08;https://testerhome.com/topics/37042&#xff09;&#xff0c; 由于种种原因 (详见此篇帖子) 当时选择了用纯 adb 命令来实现安卓自动…...

PHP合成图片,生成海报图,poster-editor使用说明

之前写过一篇使用Grafika插件生成海报图的文章&#xff0c;但是当我再次使用时&#xff0c;却发生了错误&#xff0c;回看Grafika文档&#xff0c;发现很久没更新了&#xff0c;不兼容新版的GD&#xff0c;所以改用了intervention/image插件来生成海报图。 但是后来需要对海报…...

微信小程序 - 数组 push / unshift 追加后数组返回内容为数字(数组添加后打印结果为 Number 数值类型)

前言 假设一个空数组,通过 push 方法追加了一个项,控制台打印的结果竟然是 Number 数值。 例如,以下微信小程序代码: // 源数组 var arr = [] // 追加数据 var tem = arr.push(数据)...

1、DevEco Studio 鸿蒙仓颉应用创建

1. 仓颉鸿蒙应用简介 因为仓颉是静态编译型语言&#xff0c;使用仓颉开发的应用执行效率更高。而且主打全场景&#xff0c;后续可并入仓颉生态&#xff0c;其和ArkTS都是基于ArkUI进行开发&#xff0c;最大的区别是typescript和仓颉语法间的差异。 2. 应用创建 前置条件&…...

从头开始学PHP之面向对象

首先介绍下最近情况&#xff0c;因为最近入职了且通勤距离较远&#xff0c;导致精力不够了&#xff0c;而且我发现&#xff0c;人一旦上了班&#xff0c;下班之后就不想再进行任何脑力劳动了&#xff08;对大部分牛马来说&#xff0c;精英除外&#xff09;。 话不多说进入今天的…...

C++ | Leetcode C++题解之第519题随机翻转矩阵

题目&#xff1a; 题解&#xff1a; class Solution { public:Solution(int m, int n) {this->m m;this->n n;this->total m * n;srand(time(nullptr));}vector<int> flip() {int x rand() % total;vector<int> ans;total--; // 查找位置 x 对应的…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...