Qt5.9/C++架构实例(一个简单的MCV架构应用实例)
本文主要在Qt5.9/C++桌面应用项目开发中,总结一个常用的程序架构(或框架),整个工程主要分为三大模块,分别为视图层、控制层、模型层。其中,视图层完全负责界面类的编写和展示;控制层完全负责处理逻辑,将UI界面和模型层的功能有机结合起来;模型层主要负责实现业务逻辑功能。
实现一个业务逻辑功能时,控制层是主要层;有三个主要的信号,分别是启动信号、完成信号、显示结果界面信号,具体的可以参考博主这篇文章:https://blog.csdn.net/naibozhuan3744/article/details/82383683。其中,控制层所有类都是采用单例模型,具有唯一的实例、提供一个全局接口的优点。
实现一个按钮功能步骤如下:(改进思路:控制层controller作为信号产生中转信号,建立一个控制层文件就行)
a1.UI界面点击按钮,发射一个控制器启动信号;
a2.控制层开启一条支线层,执行模型层功能函数;
a3.模型层功能函数执行完后,发射一个完成控制层信号,表明完成了该业务逻辑功能;
a4.控制层停止该支线层,并且发射一个显示完成业务逻辑UI界面信号;
a5.UI界面接收业务逻辑完成信号,显示完成功能界面。
具体的编程实例如下所述。
1.1新建一个widget工程,不要勾选ui界面。然后分别在添加视图层类(QFirsrPageWidget、QSecondPageWidget)、控制器层类(QFirsrPageController、QSecondPageController)、模型层类(QFirsrPageFunction、QSecondPageFunction),如下图所示:
1.2分别在widget.h、widget.cpp;firstpagecontroller.h、firstpagecontroller.cpp;secondpagecontroller.h、secondpagecontroller.cpp;firstpagefunction.h、firstpagefunction.cpp;secondpagefunction.h、secondpagefunction.cpp;firstpagewidget.h、firstpagewidget.cpp;secondpagewidget.h、secondpagewidget.cpp;类中添加如下代码:
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QVBoxLayout> #include <QHBoxLayout> #include <QStackedLayout> #include <QButtonGroup> class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); private: void setupUI(); void initMenu(); void initStackWidget(); QVBoxLayout *mainLayout; QButtonGroup *buttonGroup; QStackedLayout *stackLayout; // QWidget *firstPageWidget; // QWidget *secondPageWidget; private slots: void buttonGroupSlot(int); }; #endif // WIDGET_H
widget.cpp
#include "widget.h" #include "view/firstpagewidget.h" #include "view/secondpagewidget.h" #include <QPushButton> #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent) { setupUI(); } Widget::~Widget() { } void Widget::setupUI() { mainLayout = new QVBoxLayout; mainLayout->setMargin(0); mainLayout->setSpacing(0); QWidget *mainWidget = new QWidget(this); /*启动QWidget页面需要制定父对象this指针,不然会出现闪屏bug*/ mainWidget->setLayout(mainLayout); mainWidget->setObjectName("mainWidget"); mainWidget->setStyleSheet("#mainWidget{border-image:url(:/resource/main_bg.jpg)}"); /*设置主界面背景图片*/ QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); layout->setSpacing(0); layout->addWidget(mainWidget); this->setLayout(layout); /*初始化顶层菜单栏、底层功能区*/ initMenu(); initStackWidget(); } void Widget::initMenu() { const QSize btnSize(120,90); /*菜单按钮初始化*/ QPushButton *firstPageBtn = new QPushButton(tr("\n\n\n\n\n第一页")); firstPageBtn->setObjectName("firstPageBtn"); firstPageBtn->setCheckable(true); firstPageBtn->setChecked(true); firstPageBtn->setFixedSize(btnSize); firstPageBtn->setStyleSheet("QPushButton{border-image: url(:/resource/icon_page1.png) 0 0 0 0;background-repeat: no-repeat;background-position:center;border:none;color:rgb(255, 255, 255);}" "QPushButton:hover{border-image: url(:/resource/icon_page1.png) 5 0 0 0;background-repeat: no-repeat;background-position:center;border:none;color:rgb(255, 255, 255);}" "QPushButton:checked{border-image: url(:/resource/icon_page1.png) 4 0 0 0;background-repeat: no-repeat;background-position:center;border:none;color:rgb(255, 255, 255);}"); QPushButton *secondPageBtn = new QPushButton(tr("\n\n\n\n\n第二页")); secondPageBtn->setObjectName("secondPageBtn"); secondPageBtn->setCheckable(true); secondPageBtn->setFixedSize(btnSize); secondPageBtn->setStyleSheet("QPushButton{border-image: url(:/resource/icon_page2.png) 0 0 0 0;background-repeat: no-repeat;background-position:center;border:none;color:rgb(255, 255, 255);}" "QPushButton:hover{border-image: url(:/resource/icon_page2.png) 5 0 0 0;background-repeat: no-repeat;background-position:center;border:none;color:rgb(255, 255, 255);}" "QPushButton:checked{border-image: url(:/resource/icon_page2.png) 4 0 0 0;background-repeat: no-repeat;background-position:center;border:none;color:rgb(255, 255, 255);}"); /*单选菜单效果*/ buttonGroup = new QButtonGroup(); buttonGroup->setObjectName("buttonGroup"); buttonGroup->addButton(firstPageBtn); buttonGroup->addButton(secondPageBtn); buttonGroup->setExclusive(true); connect(buttonGroup,SIGNAL(buttonClicked(int)),this,SLOT(buttonGroupSlot(int))); /*容器包含*/ QHBoxLayout *menuLayout = new QHBoxLayout(); menuLayout->setMargin(0); menuLayout->setSpacing(0); menuLayout->addWidget(firstPageBtn); menuLayout->addWidget(secondPageBtn); menuLayout->addStretch(); mainLayout->addLayout(menuLayout); } void Widget::initStackWidget() { /*启动菜单栏界面*/ QFirstPageWidget *firstPageWidget = new QFirstPageWidget(this); /*启动QWidget页面需要制定父对象this指针,不然会出现闪屏bug*/ QSecondPageWidget *secondPageWidget = new QSecondPageWidget(this); stackLayout = new QStackedLayout; stackLayout->addWidget(firstPageWidget); stackLayout->addWidget(secondPageWidget); stackLayout->setCurrentIndex(0); mainLayout->addLayout(stackLayout); } void Widget::buttonGroupSlot(int) { QPushButton* checkedButton = qobject_cast<QPushButton*>(buttonGroup->checkedButton()); QString objectNameCheckedBtn = checkedButton->objectName(); if(objectNameCheckedBtn.compare(QStringLiteral("firstPageBtn"))==0) { qDebug()<<tr("单击了第一页菜单按钮"); stackLayout->setCurrentIndex(0); } else if(objectNameCheckedBtn.compare(QStringLiteral("secondPageBtn"))==0) { qDebug()<<tr("单击了第二页菜单按钮"); stackLayout->setCurrentIndex(1); } }
firstpagecontroller.h
#ifndef FIRSTPAGECONTROLLER_H #define FIRSTPAGECONTROLLER_H #include <QObject> #include <QThread> #include "model/firstpagefunction.h" class QFirstPageController : public QObject { Q_OBJECT public: static QFirstPageController* GetInstance(); signals: void startedCount_signal(); void finishedCount_signal(); void showFinishedCountUI_signal(); private: static QFirstPageController *m_instance; QFirstPageController(); void initController(); QThread *threadCount; QFirstPageFunction *firstPageFunction; private slots: void startCountSlot(); void quitCountThreadSlot(); void finishedCountThreadSlot(); }; #endif // FIRSTPAGECONTROLLER_H
firstpagecontroller.cpp
#include "firstpagecontroller.h" #include <QDebug> QFirstPageController *QFirstPageController::m_instance = new QFirstPageController(); QFirstPageController *QFirstPageController::GetInstance() { return m_instance; } QFirstPageController::QFirstPageController() { /*初始化*/ initController(); } void QFirstPageController::initController() { /*绑定信号与槽函数*/ connect(this,SIGNAL(startedCount_signal()),this,SLOT(startCountSlot())); } void QFirstPageController::startCountSlot() { /*启动一对一镜像线程*/ threadCount = new QThread; firstPageFunction = new QFirstPageFunction(); firstPageFunction->moveToThread(threadCount); connect(threadCount,SIGNAL(finished()),threadCount,SLOT(deleteLater())); connect(threadCount,SIGNAL(started()),firstPageFunction,SLOT(count_slot())); /*多线程槽函数*/ connect(this,SIGNAL(finishedCount_signal()),this,SLOT(quitCountThreadSlot())); connect(threadCount,SIGNAL(finished()),this,SLOT(finishedCountThreadSlot())); threadCount->start(); } void QFirstPageController::quitCountThreadSlot() { threadCount->quit(); threadCount->wait(); } void QFirstPageController::finishedCountThreadSlot() { qDebug()<<tr("完成计算逻辑功能!!!"); emit showFinishedCountUI_signal(); }
secondpagecontroller.h
#ifndef SECONDPAGECONTROLLER_H #define SECONDPAGECONTROLLER_H #include <QObject> class QSecondPageController : public QObject { Q_OBJECT public: static QSecondPageController* GetInstance(); signals: void count_signal(); private: static QSecondPageController *m_instance; QSecondPageController(); private slots: }; #endif // SECONDPAGECONTROLLER_H
secondpagecontroller.cpp
#include "secondpagecontroller.h" QSecondPageController *QSecondPageController::m_instance = new QSecondPageController(); QSecondPageController *QSecondPageController::GetInstance() { return m_instance; } QSecondPageController::QSecondPageController() { }
firstpagefunction.h
#ifndef FIRSTPAGEFUNCTION_H #define FIRSTPAGEFUNCTION_H #include <QObject> class QFirstPageFunction : public QObject { Q_OBJECT public: explicit QFirstPageFunction(QObject *parent = nullptr); signals: public slots: void count_slot(); }; #endif // FIRSTPAGEFUNCTION_H
firstpagefunction.cpp
#include "firstpagefunction.h" #include "controller/firstpagecontroller.h" #include <QDebug> QFirstPageFunction::QFirstPageFunction(QObject *parent) : QObject(parent) { } void QFirstPageFunction::count_slot() { int a = 2; int b = 3; QFirstPageController::GetInstance()->finishedCount_signal(); qDebug()<<tr("页面1的逻辑功能计算结果为==%1").arg(a+b); }
secondpagefunction.h
#ifndef SECONDPAGEFUNCTION_H #define SECONDPAGEFUNCTION_H #include <QObject> class QSecondPageFunction : public QObject { Q_OBJECT public: explicit QSecondPageFunction(QObject *parent = nullptr); signals: public slots: void count_slot(); }; #endif // SECONDPAGEFUNCTION_H
secondpagefunction.cpp
#include "secondpagefunction.h" #include <QDebug> QSecondPageFunction::QSecondPageFunction(QObject *parent) : QObject(parent) { } void QSecondPageFunction::count_slot() { int a = 2; int b = 3; qDebug()<<tr("页面2的逻辑功能计算结果为==%1").arg(a*b); }
firstpagewidget.h
#ifndef FIRSTPAGEWIDGET_H #define FIRSTPAGEWIDGET_H #include <QWidget> #include <QVBoxLayout> class QFirstPageWidget : public QWidget { Q_OBJECT public: explicit QFirstPageWidget(QWidget *parent = nullptr); signals: private: void setupUI(); QVBoxLayout *mainLayout; private slots: void showOneFunctionUISlot(); void showFinishedCountResultUISlot(); }; #endif // FIRSTPAGEWIDGET_H
firstpagewidget.cpp
#include "firstpagewidget.h" #include "controller/firstpagecontroller.h" #include "controller/secondpagecontroller.h" #include <QPushButton> #include <QDebug> #include <QMessageBox> QFirstPageWidget::QFirstPageWidget(QWidget *parent) : QWidget(parent) { setupUI(); } void QFirstPageWidget::setupUI() { QPushButton *firstPage = new QPushButton(tr("我是第一页的页面:点击我实现2+3计算功能(业务逻辑功能)")); connect(firstPage,SIGNAL(clicked(bool)),this,SLOT(showOneFunctionUISlot())); mainLayout = new QVBoxLayout(this); mainLayout->setMargin(0); mainLayout->setSpacing(0); mainLayout->addWidget(firstPage); mainLayout->addStretch(); /*注意:这个绑定不能放在按钮那里,否则会出现第n次点击按钮,然后发射n次信号,执行n次槽函数*/ connect(QFirstPageController::GetInstance(),SIGNAL(showFinishedCountUI_signal()),this,SLOT(showFinishedCountResultUISlot())); } void QFirstPageWidget::showOneFunctionUISlot() { /*摁下按钮,切换到新的界面*/ QFirstPageController::GetInstance()->startedCount_signal(); } void QFirstPageWidget::showFinishedCountResultUISlot() { qDebug()<<tr("显示计算后界面!!!"); QMessageBox::warning(this,QStringLiteral("结果界面"),QStringLiteral("显示计算后界面!!!"),QMessageBox::Yes,QMessageBox::No); }
secondpagewidget.h
#ifndef SECONDPAGEWIDGET_H #define SECONDPAGEWIDGET_H #include <QWidget> #include <QVBoxLayout> class QSecondPageWidget : public QWidget { Q_OBJECT public: explicit QSecondPageWidget(QWidget *parent = nullptr); signals: public slots: private: void setupUI(); QVBoxLayout *mainLayout; }; #endif // SECONDPAGEWIDGET_H
secondpagewidget.cpp
#include "secondpagewidget.h" #include <QPushButton> QSecondPageWidget::QSecondPageWidget(QWidget *parent) : QWidget(parent) { setupUI(); } void QSecondPageWidget::setupUI() { QPushButton *firstPage = new QPushButton(tr("我是第二页的页面:点击我实现2*3计算功能(业务逻辑功能)")); mainLayout = new QVBoxLayout(this); mainLayout->setMargin(0); mainLayout->setSpacing(0); mainLayout->addWidget(firstPage); mainLayout->addStretch(); }
main.cpp
#include "widget.h" #include <QApplication> #include <QIcon> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget mainWidget; mainWidget.resize(960,640); mainWidget.setWindowTitle(QString::fromUtf8("Qt/C++架构工程demo版本V1.0.0")); mainWidget.setWindowIcon(QIcon(":/resource/main_ico.ico")); mainWidget.setStyleSheet("font: bold 12px;"); mainWidget.show(); return a.exec(); }
1.2程序构建运行后,效果如下图所示
原文:https://blog.csdn.net/naibozhuan3744/article/details/82493728
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)