• 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

  • 相关阅读:
    c getline
    vim tips
    viksoe.dk UI: Become windowless
    用ls如何实现文件按时间排序查看,谢谢! AIX ChinaUnix.net
    垂直切分大小 : vertical res 30
    commandlinefu.com
    cmake 学习笔记(二) 1+1=2 博客频道 CSDN.NET
    implement split with c++
    分享:spdylay 0.3.8 发布,SDPY 的 C 语言实现
    培乐园《搜索相关性1》—在线播放—优酷网,视频高清在线观看
  • 原文地址:https://www.cnblogs.com/xiaohai123/p/16333214.html
Copyright © 2020-2023  润新知