当前位置: 首页 > 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);
}// 其他成员函数的具体实现

http://www.mrgr.cn/news/64832.html

相关文章:

  • Linux高阶——1103—修改屏蔽字信号到达及处理流程时序竞态问题
  • 算法实现 - 快速排序(Quick Sort) - 理解版
  • Django---数据库(多表关联)
  • 强化学习原理:基本概念
  • 随机生成100组N个数并对比,C++,python,matlab,pair,std::piecewise_construct
  • 深度学习基础—循环神经网络的梯度消失与解决
  • Linux入门-基础指令和权限
  • ssm044基于java和mysql的多角色学生管理系统+jsp(论文+源码)_kaic
  • 有向无环图的拓扑排序——CSP-J1真题讲解
  • 高等数学习题练习-函数的连续性
  • 支持 Mermaid 语言预览,用通义灵码画流程图
  • ERC论文阅读(04)--DialogueCRN论文阅读笔记(2024-11-03)
  • 前端学习-盒子模型(十八)
  • 【Git】如何在 Git 中高效合并分支:完整指南
  • 【学术精选】SCI期刊《Electronics》特刊“New Challenges in Remote Sensing Image Processing“
  • 手把手教你用IntelliJ IDEA 操作 DM8
  • ! [remote rejected] master -> master (pre-receive hook declined)
  • YOLOv6-4.0部分代码阅读笔记-ema.py
  • 2024年一带一路金砖技能大赛之大数据容器云开发
  • Win10 连接到 Ubuntu 黑屏无法连接 使用Rustdesk显示 No Displays 没有显示器
  • GOF的C++软件设计模式的分类和模式名称
  • 数据结构初阶排序全解
  • 力扣周赛:第422场周赛
  • roberta融合模型创新中文新闻文本标题分类
  • 优青博导团队/免费指导/一站式服务/数据分析/实验设计/论文润色/组学技术服务 、表观组分析、互作组分析、遗传转化实验、单细胞检测与生物医学
  • ctfshow——web(总结持续更新)