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

posted @ 2022-06-01 09:37  萧海~  阅读(397)  评论(0编辑  收藏  举报