当前位置: 首页 > 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 对应的…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...