Partage de technologie

Un framework MVC simple basé sur Qt

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Ce qui suit est un exemple simple de framework MVC basé sur Qt, dans lequel les opérations dans le modèle (Modèle) sont traitées dans des threads enfants. Cet exemple comprendra une vue, un contrôleur et un modèle de base.

1. Structure du projet

La structure du projet est la suivante :

MyMVCApp/
├── main.cpp
├── model.h
├── model.cpp
├── view.h
├── view.cpp
├── controller.h
├── controller.cpp
├── mainwindow.ui
├── mainwindow.h
├── mainwindow.cpp
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2. main.cpp

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. vue.h

La partie vue est principalement responsable de l’affichage des données et de l’interaction de l’utilisateur.Nous utiliserons un simpleQMainWindowEn tant que vue, elle contient un bouton et une étiquette.

#ifndef VIEW_H
#define VIEW_H

#include <QWidget>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>

class View : public QWidget
{
    Q_OBJECT

public:
    explicit View(QWidget *parent = nullptr);

    QPushButton *getButton() const;
    QLabel *getLabel() const;

private:
    QPushButton *button;
    QLabel *label;
    QVBoxLayout *layout;
};

#endif // VIEW_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

4. vue.cpp

#include "view.h"

View::View(QWidget *parent) : QWidget(parent)
{
    button = new QPushButton("Click me", this);
    label = new QLabel("Initial text", this);
    layout = new QVBoxLayout(this);

    layout->addWidget(button);
    layout->addWidget(label);

    setLayout(layout);
}

QPushButton* View::getButton() const
{
    return button;
}

QLabel* View::getLabel() const
{
    return label;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

5. fenêtre principale.h

existermainwindow.h, nous incluronsview.het intégrez-le à la fenêtre principale.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "controller.h"
#include "view.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    Controller *controller;
    View *view;
};

#endif // MAINWINDOW_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

6. fenêtre principale.cpp

existermainwindow.cpp, nous allons initialiser la vue et connecter les signaux et les emplacements du contrôleur et de la vue.

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    controller(new Controller(this)),
    view(new View(this))
{
    ui->setupUi(this);
    setCentralWidget(view);

    // Connect button click to controller slot
    connect(view->getButton(), &QPushButton::clicked, controller, &Controller::handleButtonClicked);
    
    // Connect controller signal to update label
    connect(controller, &Controller::updateLabel, view->getLabel(), &QLabel::setText);
}

MainWindow::~MainWindow()
{
    delete ui;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

7. contrôleur.h

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <QObject>
#include "model.h"

class Controller : public QObject
{
    Q_OBJECT

public:
    explicit Controller(QObject *parent = nullptr);

signals:
    void updateLabel(const QString &text);

public slots:
    void handleButtonClicked();

private:
    Model *model;
};

#endif // CONTROLLER_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

8. contrôleur.cpp

#include "controller.h"

Controller::Controller(QObject *parent) : QObject(parent), model(new Model(this))
{
    // Connect model signal to controller signal
    connect(model, &Model::dataProcessed, this, &Controller::updateLabel);
}

void Controller::handleButtonClicked()
{
    model->processData();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

9. modèle.h

#ifndef MODEL_H
#define MODEL_H

#include <QObject>
#include <QThread>

class Model : public QObject
{
    Q_OBJECT

public:
    explicit Model(QObject *parent = nullptr);
    ~Model();

    void processData();

signals:
    void dataProcessed(const QString &result);

private:
    QThread workerThread;
};

#endif // MODEL_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

10. modèle.cpp

#include "model.h"
#include <QTimer>

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork()
    {
        // Simulate long-running task
        QThread::sleep(2);
        emit resultReady("Data processed in background thread");
    }

signals:
    void resultReady(const QString &result);
};

Model::Model(QObject *parent) : QObject(parent)
{
    Worker *worker = new Worker;
    worker->moveToThread(&workerThread);

    connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
    connect(this, &Model::operate, worker, &Worker::doWork);
    connect(worker, &Worker::resultReady, this, &Model::dataProcessed);

    workerThread.start();
}

Model::~Model()
{
    workerThread.quit();
    workerThread.wait();
}

void Model::processData()
{
    emit operate();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

11. Classe ouvrière

existermodel.cppDéfinir un dansWorkerClasse pour effectuer des tâches dans les threads enfants.

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork()
    {
        // Simulate long-running task
        QThread::sleep(2);
        emit resultReady("Data processed in background thread");
    }

signals:
    void resultReady(const QString &result);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Résumer

Cet exemple inclut View, Controller et Model.
La vue est responsable de l'affichage des données et de l'interaction de l'utilisateur, le contrôleur traite les entrées de l'utilisateur et met à jour la vue, et le modèle traite les données dans un thread enfant et demande au contrôleur de mettre à jour la vue.
Vous pouvez étendre ce framework selon vos besoins, en ajoutant plus de fonctionnalités et de complexité.
J'espère que cet exemple vous aidera !