Logs
Consultez les logs.
OK
Liste des données
Consultez la liste des données.
OK
Loading...
Formulaire
Saisissez vos données.
Enregistrer
Annuler

Apprendre Qt

Vues
291

Introduction


C++ est un langage de programmation orientée objet. Il offre la possibilité d'avoir le contrôle total sur la gestion de la mémoire.


### Travailler avec Qt


Qt est un gestionnaire d'interfaces homme machine développé en C++ et étendu à plusieurs langages de programmation. Il permet de créer des interfaces homme machine multiplateformes bureau ou mobile sans changer la base de code. 


Changer le style d'apparence des fenêtres en C++ sous Qt


Qt est une librairie de création d'interfaces homme machine prenant en charge le changement dynamique de style d'apparence des fenêtres d'une application. QStyleFactory peut être utilisé pour lister les styles d'apparence disponible sur le système. Alors que, QApplication peut être utilisé pour appliquer dynamiquement un style d'apparence à l'ensemble des fenêtres d'une application. 


Gestion du programme principal 


// main.cpp (Editer le programme principal)
...
#include "cMainWindow.h"
#include <QApplication>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    cMainWindow *oMainWindow = new cMainWindow;
    oMainWindow->resize(400, 200);
    oMainWindow->show();
    return app.exec();
}
...

Gestion de la fenêtre principale


// cMainWindow.h (Editer la fenêtre principale)
...
#pragma once

#include <QMainWindow>
#include "cActions.h"

class QLabel;

namespace Ui
{
    class cMainWindow;
}

class cMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    using sAction = cActions::sAction;

public:
    explicit cMainWindow(QWidget *parent = 0);
    ~cMainWindow();

private slots:
    void on_actionHomePage_triggered();
    void on_actionThemePage_triggered();
    void onAction(const sAction &_action);

private:
    Ui::cMainWindow *ui;
    QLabel *m_themeStatus;
};
...

// cMainWindow.cpp (Editer la fenêtre principale)
...
#include "cMainWindow.h"
#include "ui_cMainWindow.h"
#include <QStyleFactory>
#include <QMessageBox>
#include <QLabel>

const QString ACTION_APPLY_STYLE = "ACTION_APPLY_STYLE";

cMainWindow::cMainWindow(QWidget *parent)
    : QMainWindow(parent),
      ui(new Ui::cMainWindow)
{
    ui->setupUi(this);
    ui->stackedWidget->setCurrentWidget(ui->pageHome);
    ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);

    QStringList oThemes = QStyleFactory::keys();
    for (const auto &oTheme : oThemes)
    {
        qDebug() << "La detection du style d'apparence a reussi."
                 << "|theme=" << oTheme;

        ui->tableWidget->insertRow(ui->tableWidget->rowCount());
        QTableWidgetItem *oTableWidgetItem = new QTableWidgetItem(oTheme);
        ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, 0, oTableWidgetItem);

        cActions *oActions = new cActions;
        oActions->addAction(oTheme, ACTION_APPLY_STYLE, "Appliquer le style");
        oActions->initActions();
        connect(oActions, &cActions::emitAction, this, &cMainWindow::onAction);

        ui->tableWidget->setCellWidget(ui->tableWidget->rowCount() - 1, 1, oActions);
    }

    qDebug() << "La detection du style en cours est termine."
             << "|style=" << qApp->style()->name();

    m_themeStatus = new QLabel;
    statusBar()->addWidget(m_themeStatus);
    m_themeStatus->setText(tr("Thème : %1").arg(qApp->style()->name()));
}

cMainWindow::~cMainWindow()
{
    delete ui;
}

void cMainWindow::on_actionHomePage_triggered()
{
    ui->stackedWidget->setCurrentWidget(ui->pageHome);
}

void cMainWindow::on_actionThemePage_triggered()
{
    ui->stackedWidget->setCurrentWidget(ui->pageTheme);
}

void cMainWindow::onAction(const sAction &_action)
{
    qDebug() << "L'action est en cours d'application."
             << "|data=" << _action.data
             << "|key=" << _action.key
             << "|text=" << _action.text;
    if (_action.key == ACTION_APPLY_STYLE)
    {
        qApp->setStyle(_action.data);
        m_themeStatus->setText(tr("Thème : %1").arg(qApp->style()->name()));
    }
}
...

// cMainWindow.ui (Editer le menu général)
image.png

// cMainWindow.ui (Editer la liste des styles)
image.png

Gestion du bouton des actions


// cActions.h (Editer le bouton des actions)
...
#pragma once

#include <QWidget>
#include <QVector>
#include <QMap>

namespace Ui
{
    class cActions;
}

class cActions : public QWidget
{
    Q_OBJECT

public:
    struct sAction
    {
        QString data;
        QString key;
        QString text;
    };

public:
    explicit cActions(QWidget *parent = 0);
    ~cActions();
    void addAction(const QString &_data, const QString &_key, const QString &_text);
    void initActions();

private:
    bool isActive(const QString &_key) const;
    bool loadAction(const QString &_key, sAction &_action) const;

private slots:
    void onAction();

signals:
    void emitAction(sAction);

private:
    Ui::cActions *ui;
    QVector<sAction> m_actions;
    QMap<QAction *, QString> m_keys;
};
...

// cActions.cpp (Editer le bouton des actions)
...
#include "cActions.h"
#include "ui_cActions.h"
#include <QMenu>

cActions::cActions(QWidget *parent)
    : QWidget(parent),
      ui(new Ui::cActions)
{
    ui->setupUi(this);
    ui->layActions->setAlignment(Qt::AlignCenter);
}

cActions::~cActions()
{
    delete ui;
}

void cActions::addAction(const QString &_data, const QString &_key, const QString &_text)
{
    if (!isActive(_key))
    {
        sAction oAction{_data, _key, _text};
        m_actions.push_back(oAction);
    }
    else
    {
        qDebug() << "L'action a ete deja ajoutee a la liste."
                 << "|data=" << _data
                 << "|key=" << _key
                 << "|text=" << _text;
    }
}

void cActions::initActions()
{
    if (m_actions.isEmpty())
    {
        qDebug() << "Aucune action n'a ete ajoutee à liste";
        return;
    }

    QMenu *oMenu = new QMenu(this);

    for (const auto &oAction : m_actions)
    {
        QAction *iAction = new QAction(oAction.text);
        iAction->setData(oAction.data);
        connect(iAction, &QAction::triggered, this, &cActions::onAction);
        m_keys[iAction] = oAction.key;
        oMenu->addAction(iAction);
    }

    ui->btnActions->setMenu(oMenu);
}

bool cActions::isActive(const QString &_key) const
{
    for (const auto &oAction : m_actions)
    {
        if (oAction.key == _key)
        {
            return true;
        }
    }
    return false;
}

bool cActions::loadAction(const QString &_key, sAction &_action) const
{
    for (const auto &oAction : m_actions)
    {
        if (oAction.key == _key)
        {
            _action = oAction;
            return true;
        }
    }
    return false;
}

void cActions::onAction()
{
    QAction *oAction = qobject_cast<QAction *>(sender());
    QString oKey = m_keys[oAction];
    sAction iAction;
    if (loadAction(oKey, iAction))
    {
        emit emitAction(iAction);
    }
}
...

// cActions.ui (Editer le bouton des actions)
image.png

Gestion du fichier CMake


// CMakeLists.txt (Editer le fichier CMake)
...
cmake_minimum_required(VERSION 3.10.0)
project(rdvcpp VERSION 0.1.0 LANGUAGES C CXX)

set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_PREFIX_PATH "C:/Qt/6.5.2/msvc2019_64/lib/cmake")

find_package(Qt6 REQUIRED COMPONENTS
    Widgets
)

qt_wrap_ui(UI_FILES
    cMainWindow.ui
    cActions.ui
)

add_executable(rdvcpp
    main.cpp
    cMainWindow.cpp
    cActions.cpp
    resources.qrc
    ${UI_FILES}
)

target_link_libraries (rdvcpp
    Qt6::Widgets
)
...

Gestion du fichier ressource


// resources.qrc (Editer le fichier ressource)
...
<RCC>
  <qresource prefix="/img">
    <file alias="logo.png">data/img/logo.png</file>
  </qresource>
</RCC>
...


Exécuter le projet


// Terminal (Exécuter le projet)
...
rdvcpp.exe
...

// Application (Fiche du menu à propos)
image.png

// Application (Apparence du style [WindowsVista])
image.png

// Application (Apparence du style [Windows])
image.png

// Application (Apparence du style [Fusion])
image.png

Démo de l'application


https://www.youtube.com/watch?v=MAE01f4tfo0


Afficher une fenêtre d'aide HTML en C++ sous Qt


Qt est une librairie de création d'interfaces homme machine prenant en charge l'affichage de texte HTML dans une fenêtre de navigation web. QTextBrowser peut être utilisé pour afficher le contenu d'un fichier d'aide au format HTML avec la possibilité d'y insérer des liens de navigation interne dans le document.


Gestion du programme principal


// main.cpp (Editer le programme principal)
...
#include "cMainWindow.h"
#include <QApplication>
#include <QFontDatabase>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    QString oFontFile(":/font/fontawesome-webfont.ttf");
    int id = QFontDatabase::addApplicationFont(oFontFile);
    if (id == -1)
    {
        qDebug() << "Le chargement de la police a echoue."
                 << "|fontFile=" << oFontFile;
    }
    else
    {
        QStringList oFontFamilies = QFontDatabase::applicationFontFamilies(id);
        qDebug() << "Le chargement de la police a reussi."
                 << "|fontFile=" << oFontFile
                 << "|fontFamilies=" << oFontFamilies;
    }

    cMainWindow *oMainWindow = new cMainWindow;
    oMainWindow->resize(400, 200);
    oMainWindow->show();
    return app.exec();
}
...

Gestion de la fenêtre principale


// cMainWindow.h (Editer la fenêtre principale)
...
#pragma once

#include <QMainWindow>

class cHelpWindow;

namespace Ui
{
    class cMainWindow;
}

class cMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit cMainWindow(QWidget *parent = 0);
    ~cMainWindow();

private slots:
    void on_actionHelpApp_triggered();
    void on_actionAboutApp_triggered();
    void on_actionAboutQt_triggered();

private:
    Ui::cMainWindow *ui;
    cHelpWindow *m_helpWindow;
};
...

// cMainWindow.cpp (Editer la fenêtre principale)
...
#include "cMainWindow.h"
#include "ui_cMainWindow.h"
#include "cHelpWindow.h"
#include <QMessageBox>
#include <QFile>
#include <QFontDatabase>
#include <QDebug>

cMainWindow::cMainWindow(QWidget *parent)
    : QMainWindow(parent),
      ui(new Ui::cMainWindow)
{
    ui->setupUi(this);
    QFile oFile(":/help/fr.html");
    if (!oFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "Le fichier d'aide est introuvable."
                 << "filename=" << oFile.fileName();
        return;
    }
    QByteArray oFileData = oFile.readAll();
    m_helpWindow = new cHelpWindow(QString(oFileData), this);
}

cMainWindow::~cMainWindow()
{
    delete ui;
}

void cMainWindow::on_actionHelpApp_triggered()
{
    m_helpWindow->exec();
}

void cMainWindow::on_actionAboutApp_triggered()
{
    QMessageBox::about(this, "A propos de l'application ",
                       "<b>ReadySCOPE - v1.0</b><br>"
                       "Oscilloscope numérique<br><br>"
                       "Produit par <a href='https://readydev.ovh/home'>ReadyDEV</a><br>"
                       "Plateforme de Développement Continu");
}

void cMainWindow::on_actionAboutQt_triggered()
{
    QMessageBox::aboutQt(this);
}
...

// cMainWindow.ui (Editer le menu à propos)
image.png

Gestion de la fenêtre d'aide de l'application


// cHelpWindow.h (Editer la fenêtre d'aide)
...
#pragma once

#include <QDialog>

class cFloatButton;

namespace Ui
{
    class cHelpWindow;
}

class cHelpWindow : public QDialog
{
    Q_OBJECT

public:
    explicit cHelpWindow(const QString &_message, QWidget *parent = 0);
    ~cHelpWindow();

protected:
    void resizeEvent(QResizeEvent *event);

private slots:
    void onOpenTopLink();
    void onOpenBottomLink();

private:
    Ui::cHelpWindow *ui;
    QString m_message;
    cFloatButton *m_topLink;
    cFloatButton *m_bottomLink;
};
...

// cHelpWindow.cpp (Editer la fenêtre d'aide)
...
#include "cHelpWindow.h"
#include "ui_cHelpWindow.h"
#include "cFloatButton.h"
#include <QLabel>
#include <QResizeEvent>
#include <QScrollBar>

using namespace std::chrono_literals;

cHelpWindow::cHelpWindow(const QString &_message, QWidget *parent)
    : QDialog(parent),
      ui(new Ui::cHelpWindow),
      m_message(_message)
{
    ui->setupUi(this);
    ui->txtHelp->setHtml(m_message);
    resize(600, 300);
    m_bottomLink = new cFloatButton(ICON_FA_CHEVRON_DOWN, this);
    connect(m_bottomLink, &cFloatButton::emitClicked, this, &cHelpWindow::onOpenBottomLink);
    m_topLink = new cFloatButton(ICON_FA_CHEVRON_UP, this);
    connect(m_topLink, &cFloatButton::emitClicked, this, &cHelpWindow::onOpenTopLink);
}

cHelpWindow::~cHelpWindow()
{
    delete ui;
}

void cHelpWindow::resizeEvent(QResizeEvent *event)
{
    m_bottomLink->move(width() - 75 - 50, height() - 85);
    m_topLink->move(width() - 75, height() - 85);
}

void cHelpWindow::onOpenTopLink()
{
    QScrollBar *oScrollBar = ui->txtHelp->verticalScrollBar();
    oScrollBar->setValue(0);
}

void cHelpWindow::onOpenBottomLink()
{
    QScrollBar *oScrollBar = ui->txtHelp->verticalScrollBar();
    oScrollBar->setValue(oScrollBar->maximum());
}
...

// cHelpWindow.ui (Editer la fenêtre d'aide)
image.png

Gestion du bouton flottant


// cFloatButton.h (Editer le bouton flotant)
...
#pragma once

#include <QWidget>
#include "IconsFontAwesome4.h"

namespace Ui
{
    class cFloatButton;
}

class cFloatButton : public QWidget
{
    Q_OBJECT

public:
    explicit cFloatButton(const QString &_iconLabel, QWidget *parent = 0);
    ~cFloatButton();

protected:
    bool eventFilter(QObject *object, QEvent *event);

signals:
    void emitClicked();

private:
    Ui::cFloatButton *ui;
    QString m_iconLabel;
};
...

// cFloatButton.cpp (Editer le bouton flotant)
...
#include "cFloatButton.h"
#include "ui_cFloatButton.h"
#include <QMouseEvent>

using namespace std::chrono_literals;

cFloatButton::cFloatButton(const QString &_iconLabel, QWidget *parent)
    : QWidget(parent),
      ui(new Ui::cFloatButton),
      m_iconLabel(_iconLabel)
{
    ui->setupUi(this);
    adjustSize();

    QFont font;
    font.setFamily("FontAwesome");
    font.setPixelSize(20);

    ui->lblButton->setFont(font);
    ui->lblButton->setText(m_iconLabel);
    ui->lblButton->installEventFilter(this);
}

cFloatButton::~cFloatButton()
{
    delete ui;
}

bool cFloatButton::eventFilter(QObject *object, QEvent *event)
{
    if (object == ui->lblButton && event->type() == QEvent::MouseButtonRelease)
    {
        QMouseEvent *oMouseEvent = static_cast<QMouseEvent *>(event);
        if (oMouseEvent->button() == Qt::LeftButton)
        {
            emit emitClicked();
            return true;
        }
    }
    return false;
}
...

// cFloatButton.ui (Editer le bouton flotant)
image.png

Gestion du fichier CMake


// CMakeLists.txt (Editer le fichier CMake)
...
cmake_minimum_required(VERSION 3.10.0)
project(rdvcpp VERSION 0.1.0 LANGUAGES C CXX)

set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_PREFIX_PATH "C:/Qt/6.5.2/msvc2019_64/lib/cmake")

find_package(Qt6 REQUIRED COMPONENTS
    Widgets
)

qt_wrap_ui(UI_FILES
    cMainWindow.ui
    cHelpWindow.ui
    cFloatButton.ui
)

add_executable(rdvcpp
    main.cpp
    cMainWindow.cpp
    cHelpWindow.cpp
    cFloatButton.cpp
    resources.qrc
    ${UI_FILES}
)

target_link_libraries (rdvcpp
    Qt6::Widgets
)
...

Gestion du fichier ressource


// resources.qrc (Editer le fichier ressource)
...
<RCC>
  <qresource prefix="/img">
    <file alias="logo.png">data/img/logo.png</file>
  </qresource>
  <qresource prefix="/help">
    <file alias="fr.html">data/help/fr.html</file>
  </qresource>
  <qresource prefix="/font">
    <file alias="fontawesome-webfont.ttf">data/font/fontawesome-webfont.ttf</file>
  </qresource>
</RCC>
...

Exécution du projet


// Terminal (Exécuter le projet)
...
rdvcpp.exe
...

// Application (Fiche du menu à propos)
image.png

// Application (Fiche de l'aide de l'application)
image.png

// Application (Fiche à propos de l'application)
image.png

// Application (Fiche à propos de Qt)
image.png

Démo de l'application


https://www.youtube.com/watch?v=Qctn_INIvPg


Gérer une communication port série en C++ sous Qt


Qt est une librairie de création d'interfaces homme machine prenant en charge la gestion de la communication port série. QSerialPort peut être utilisé pour concevoir en toute simplicité une interface de contrôle d'un système via le port série. Dans ce tutoriel, nous utilisons QSerialPort pour établir 2 connexions à partir d'une paire de ports série afin de mettre en place un système chat.


Gestion du programme principal


// main.cpp (Editer le fichier source)
...
#include "cMainWindow.h"
#include <QApplication>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    cMainWindow *oMainWindow = new cMainWindow;
    oMainWindow->resize(600, 400);
    oMainWindow->show();
    return app.exec();
}
...

Gestion de la fenêtre principale


// cMainWindow.h (Editer la fenêtre principale)
...
#pragma once

#include <QMainWindow>
#include <QtSerialPort/QSerialPort>
#include <QVector>
#include <QMap>

namespace Ui
{
    class cMainWindow;
}

class cMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit cMainWindow(QWidget *parent = 0);
    ~cMainWindow();

private:
    bool isActive(const QString &_portName) const;
    void addConnection(const QString &_portName);
    void addPortToTab(const QString &_portName);
    bool loadConnection(const QString &_portName, QSerialPort **_serialPort) const;
    bool loadPortToTab(const QString &_portName, QWidget **_tabWidget) const;
    bool loadPortToTab(QWidget *_oTabWidget, QString &_portName) const;
    bool loadPortToTab(const QString &_portName, QLayout **_layout) const;
    void showSendMessageTab(const QString &_portName) const;
    void clearOpenConnection();
    void clearSendMessagePort1();
    void clearSendMessagePort2();

private slots:
    void on_actionOpenConnection_triggered();
    void on_actionDisplayConnection_triggered();
    void on_btnOpenConnection_clicked();
    void on_btnSendMessagePort1_clicked();
    void on_btnSendMessagePort2_clicked();
    void onReadyData();
    void onErrorOccurred(QSerialPort::SerialPortError error);
    void onSendMessage(QAction *_action);

private:
    Ui::cMainWindow *ui;
    QVector<QSerialPort *> m_connections;
    QMap<QString, QWidget *> m_portToTab;
};
...

// cMainWindow.cpp (Editer la fenêtre principale)
...
#include "cMainWindow.h"
#include "ui_cMainWindow.h"
#include "cPortAction.h"
#include "cMessageSend.h"
#include "cMessageRecv.h"
#include <QMessageBox>
#include <QScrollBar>

cMainWindow::cMainWindow(QWidget *parent)
    : QMainWindow(parent),
      ui(new Ui::cMainWindow)
{
    ui->setupUi(this);
    ui->stackedWidget->setCurrentWidget(ui->pageHome);
    ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->tabWidget->setCurrentWidget(ui->tabSendMessagePort1);
    ui->messageLayoutPort1->setAlignment(Qt::AlignTop);
    ui->messageLayoutPort2->setAlignment(Qt::AlignTop);
}

cMainWindow::~cMainWindow()
{
    delete ui;
}

bool cMainWindow::isActive(const QString &_portName) const
{
    for (QSerialPort *oSerialPort : m_connections)
    {
        if (oSerialPort->portName() == _portName)
        {
            if (oSerialPort->isOpen())
                return true;
        }
    }
    return false;
}

void cMainWindow::addConnection(const QString &_portName)
{
    ui->tableWidget->insertRow(ui->tableWidget->rowCount());
    QTableWidgetItem *oTableWidgetItem = new QTableWidgetItem(_portName);
    ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, 0, oTableWidgetItem);

    cPortAction *oPortAction = new cPortAction(_portName);
    connect(oPortAction, &cPortAction::emitSendMessage, this, &cMainWindow::onSendMessage);

    ui->tableWidget->setCellWidget(ui->tableWidget->rowCount() - 1, 1, oPortAction);
}

void cMainWindow::addPortToTab(const QString &_portName)
{
    switch (m_portToTab.size())
    {
    case 0:
        m_portToTab[_portName] = ui->tabSendMessagePort1;
        ui->tabWidget->setTabText(ui->tabWidget->indexOf(ui->tabSendMessagePort1), _portName);
        break;
    case 1:
        m_portToTab[_portName] = ui->tabSendMessagePort2;
        ui->tabWidget->setTabText(ui->tabWidget->indexOf(ui->tabSendMessagePort2), _portName);
        break;
    default:
        break;
    }
}

bool cMainWindow::loadConnection(const QString &_portName, QSerialPort **_serialPort) const
{
    for (QSerialPort *oSerialPort : m_connections)
    {
        if (oSerialPort->portName() == _portName)
        {
            if (oSerialPort->isOpen())
            {
                (*_serialPort) = oSerialPort;
                return true;
            }
        }
    }
    return false;
}

bool cMainWindow::loadPortToTab(const QString &_portName, QWidget **_tabWidget) const
{
    QMap<QString, QWidget *>::const_iterator it;
    for (it = m_portToTab.begin(); it != m_portToTab.end(); ++it)
    {
        if (it.key() == _portName)
        {
            (*_tabWidget) = it.value();
            return true;
        }
    }
    return false;
}

bool cMainWindow::loadPortToTab(QWidget *_oTabWidget, QString &_portName) const
{
    QMap<QString, QWidget *>::const_iterator it;
    for (it = m_portToTab.begin(); it != m_portToTab.end(); ++it)
    {
        if (it.value() == _oTabWidget)
        {
            _portName = it.key();
            return true;
        }
    }
    return false;
}

bool cMainWindow::loadPortToTab(const QString &_portName, QLayout **_layout) const
{
    QWidget *oTabWidget;
    if (!loadPortToTab(_portName, &oTabWidget))
        return false;

    if (oTabWidget == ui->tabSendMessagePort1)
    {
        (*_layout) = ui->messageLayoutPort1;
        return true;
    }
    if (oTabWidget == ui->tabSendMessagePort2)
    {
        (*_layout) = ui->messageLayoutPort2;
        return true;
    }

    return false;
}

void cMainWindow::showSendMessageTab(const QString &_portName) const
{
    QWidget *oTabWidget;
    if (!loadPortToTab(_portName, &oTabWidget))
        return;
    ui->tabWidget->setTabVisible(ui->tabWidget->indexOf(ui->tabSendMessagePort1), (oTabWidget == ui->tabSendMessagePort1));
    ui->tabWidget->setTabVisible(ui->tabWidget->indexOf(ui->tabSendMessagePort2), (oTabWidget == ui->tabSendMessagePort2));
}

void cMainWindow::clearOpenConnection()
{
    ui->edtPortName->clear();
}

void cMainWindow::clearSendMessagePort1()
{
    ui->edtSendMessagePort1->clear();
}

void cMainWindow::clearSendMessagePort2()
{
    ui->edtSendMessagePort2->clear();
}

void cMainWindow::on_actionOpenConnection_triggered()
{
    if (m_connections.size() == 2)
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("Le nombre maximal de connexions est atteint."));
        return;
    }

    ui->stackedWidget->setCurrentWidget(ui->pageOpenConnection);
}

void cMainWindow::on_actionDisplayConnection_triggered()
{
    ui->stackedWidget->setCurrentWidget(ui->pageDisplayConnection);
}

void cMainWindow::on_btnOpenConnection_clicked()
{
    QString oPortName = ui->edtPortName->text();

    if (oPortName.isEmpty())
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("Le nom du port est obligatoire."));
        return;
    }

    if (isActive(oPortName))
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("Le port série est déjà ouvert."));
        return;
    }

    QSerialPort *oSerialPort = new QSerialPort(this);
    connect(oSerialPort, &QSerialPort::readyRead, this, &cMainWindow::onReadyData);
    connect(oSerialPort, &QSerialPort::errorOccurred, this, &cMainWindow::onErrorOccurred);

    oSerialPort->setPortName(oPortName);
    oSerialPort->setBaudRate(QSerialPort::Baud9600);
    oSerialPort->setDataBits(QSerialPort::Data8);
    oSerialPort->setFlowControl(QSerialPort::NoFlowControl);
    oSerialPort->setParity(QSerialPort::NoParity);
    oSerialPort->setStopBits(QSerialPort::OneStop);
    oSerialPort->open(QIODevice::ReadWrite);

    if (!oSerialPort->isOpen())
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("La connexion au port série a échoué."));

        return;
    }

    QMessageBox::information(this, tr("Messages d'informations"),
                             tr("La connexion au port série a réussi."));

    m_connections.push_back(oSerialPort);
    addConnection(oPortName);
    addPortToTab(oPortName);
    clearOpenConnection();
    ui->stackedWidget->setCurrentWidget(ui->pageHome);
}

void cMainWindow::on_btnSendMessagePort1_clicked()
{
    QString oMessage = ui->edtSendMessagePort1->toPlainText();

    if (oMessage.isEmpty())
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("Le message est obligatoire."));

        return;
    }

    QString oPortName;

    if (!loadPortToTab(ui->tabSendMessagePort1, oPortName))
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("Le nom du port est inconnu."));

        return;
    }

    QSerialPort *oSerialPort;
    if (!loadConnection(oPortName, &oSerialPort))
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("La connexion port série est introuvable."));
        return;
    }

    cMessageSend *oMessageSend = new cMessageSend(oMessage);
    ui->messageLayoutPort1->addWidget(oMessageSend);
    ui->scrollAreaPort1->widget()->adjustSize();
    qApp->processEvents();
    ui->scrollAreaPort1->verticalScrollBar()->setValue(ui->scrollAreaPort1->verticalScrollBar()->maximum());

    oSerialPort->write(oMessage.toUtf8());

    clearSendMessagePort1();

    qDebug() << "L'envoi de message est termine."
             << "|portName=" << oSerialPort->portName()
             << "|message=" << oMessage.left(50);
}

void cMainWindow::on_btnSendMessagePort2_clicked()
{
    QString oMessage = ui->edtSendMessagePort2->toPlainText();

    if (oMessage.isEmpty())
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("Le message est obligatoire."));
        return;
    }

    QString oPortName;

    if (!loadPortToTab(ui->tabSendMessagePort2, oPortName))
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("Le nom du port est inconnu."));

        return;
    }

    QSerialPort *oSerialPort;
    if (!loadConnection(oPortName, &oSerialPort))
    {
        QMessageBox::critical(this, tr("Messages d'erreurs"),
                              tr("La connexion port série est introuvable."));
        return;
    }

    cMessageSend *oMessageSend = new cMessageSend(oMessage);
    ui->messageLayoutPort2->addWidget(oMessageSend);
    ui->scrollAreaPort2->widget()->adjustSize();
    qApp->processEvents();
    ui->scrollAreaPort2->verticalScrollBar()->setValue(ui->scrollAreaPort2->verticalScrollBar()->maximum());

    oSerialPort->write(oMessage.toUtf8());

    clearSendMessagePort2();

    qDebug()
        << "L'envoi de message est termine."
        << "|portName=" << oSerialPort->portName()
        << "|message=" << oMessage.left(50);
}

void cMainWindow::onReadyData()
{
    QSerialPort *oSerialPort = qobject_cast<QSerialPort *>(sender());
    QByteArray oMessage = oSerialPort->readAll();
    QString oPortName = oSerialPort->portName();
    QLayout *oMessageLayout;

    if (!loadPortToTab(oSerialPort->portName(), &oMessageLayout))
        return;

    cMessageRecv *oMessageRecv = new cMessageRecv(oMessage);
    oMessageLayout->addWidget(oMessageRecv);

    qDebug() << "La reception de message est termine."
             << "|portName=" << oSerialPort->portName()
             << "|message=" << oMessage.left(50);
}

void cMainWindow::onErrorOccurred(QSerialPort::SerialPortError error)
{
    if (error != QSerialPort::NoError)
    {
        QSerialPort *oSerialPort = qobject_cast<QSerialPort *>(sender());
        qDebug() << "La connexion au port serie a echoue."
                 << "|errorCode=" << error
                 << "|portName=" << oSerialPort->portName();
    }
}

void cMainWindow::onSendMessage(QAction *_action)
{
    QString oPortName = _action->data().toString();
    QSerialPort *oSerialPort;
    if (loadConnection(oPortName, &oSerialPort))
    {
        ui->stackedWidget->setCurrentWidget(ui->pageSendMessage);
        showSendMessageTab(oPortName);
        qDebug() << "L'envoi de message a demarre."
                 << "|portName=" << oSerialPort->portName();
    }
}
...

// cMainWindow.ui (Editer le menu)
image.png

// cMainWindow.ui (Editer la liste des ports série)
image.png

// cMainWindow.ui (Editer l'ouverture d'un port série)
image.png

// cMainWindow.ui (Editer l'envoi des messages sur le port série 1)
image.png

// cMainWindow.ui (Editer l'envoi des messages sur le port série 2)
image.png

Gestion des actions associées à un port série


// cPortAction.h (Editer les actions associées à un port série)
...
#pragma once

#include <QWidget>

namespace Ui
{
    class cPortAction;
}

class cPortAction : public QWidget
{
    Q_OBJECT

public:
    explicit cPortAction(const QString &_portName, QWidget *parent = 0);
    ~cPortAction();

private:
    void initActions();

private slots:
    void onSendMessage();

signals:
    void emitSendMessage(QAction *);

private:
    Ui::cPortAction *ui;
    QString m_portName;
};
...

// cPortAction.cpp (Editer les actions associées à un port série)
...
#include "cPortAction.h"
#include "ui_cPortAction.h"
#include <QMenu>

cPortAction::cPortAction(const QString &_portName, QWidget *parent)
    : QWidget(parent),
      ui(new Ui::cPortAction),
      m_portName(_portName)
{
    ui->setupUi(this);
    ui->layActions->setAlignment(Qt::AlignCenter);
    initActions();
}

cPortAction::~cPortAction()
{
    delete ui;
}

void cPortAction::initActions()
{
    QMenu *oMenu = new QMenu(this);

    QAction *oActions = new QAction("Envoyer un message");
    oActions->setData(m_portName);
    oMenu->addAction(oActions);
    connect(oActions, &QAction::triggered, this, &cPortAction::onSendMessage);

    ui->btnActions->setMenu(oMenu);
}

void cPortAction::onSendMessage()
{
    QAction *oActions = qobject_cast<QAction *>(sender());
    emit emitSendMessage(oActions);
}
...

// cPortAction.ui (Editer les actions)
image.png

Gestion de l'envoi de message


// cMessageSend.h (Editer l'envoi des messages)
...
#pragma once

#include <QWidget>

namespace Ui
{
    class cMessageSend;
}

class cMessageSend : public QWidget
{
    Q_OBJECT

public:
    explicit cMessageSend(const QString &_message, QWidget *parent = 0);
    ~cMessageSend();

private:
    Ui::cMessageSend *ui;
    QString m_message;
};
...

// cMessageSend.h (Editer l'envoi des messages)
...
#include "cMessageSend.h"
#include "ui_cMessageSend.h"

using namespace std::chrono_literals;

cMessageSend::cMessageSend(const QString &_message, QWidget *parent)
    : QWidget(parent),
      ui(new Ui::cMessageSend),
      m_message(_message)
{
    ui->setupUi(this);
    ui->layLogo->setAlignment(Qt::AlignTop);
    ui->lblMessage->setText(m_message);
}

cMessageSend::~cMessageSend()
{
    delete ui;
}
...

// cMessageSend.ui (Editer l'envoi des messages)
image.png

Gestion de la réception des messages


// cMessageRecv.h (Editer la réception des messages)
...
#pragma once

#include <QWidget>

namespace Ui
{
    class cMessageRecv;
}

class cMessageRecv : public QWidget
{
    Q_OBJECT

public:
    explicit cMessageRecv(const QString &_message, QWidget *parent = 0);
    ~cMessageRecv();

private:
    Ui::cMessageRecv *ui;
    QString m_message;
};
...

// cMessageRecv.cpp (Editer la réception des messages)
...
#include "cMessageRecv.h"
#include "ui_cMessageRecv.h"

using namespace std::chrono_literals;

cMessageRecv::cMessageRecv(const QString &_message, QWidget *parent)
    : QWidget(parent),
      ui(new Ui::cMessageRecv),
      m_message(_message)
{
    ui->setupUi(this);
    ui->layLogo->setAlignment(Qt::AlignTop);
    ui->lblMessage->setText(m_message);
}

cMessageRecv::~cMessageRecv()
{
    delete ui;
}
...

// cMessageRecv.ui (Editer la réception des messages)
image.png

Gestion du fichier CMake


// CMakeLists.txt (Editer le fichier CMake)
...
cmake_minimum_required(VERSION 3.10.0)
project(rdvcpp VERSION 0.1.0 LANGUAGES C CXX)

set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_PREFIX_PATH "C:/Qt/6.5.2/msvc2019_64/lib/cmake")

find_package(Qt6 REQUIRED COMPONENTS
    Widgets
    SerialPort
)

qt_wrap_ui(UI_FILES
    cMainWindow.ui
    cPortAction.ui
    cMessageSend.ui
    cMessageRecv.ui
)

add_executable(rdvcpp
    main.cpp
    cMainWindow.cpp
    cPortAction.cpp
    cMessageSend.cpp
    cMessageRecv.cpp
    resources.qrc
    ${UI_FILES}
)

target_link_libraries (rdvcpp
    Qt6::Widgets
    Qt6::SerialPort
)
...

Gestion du fichier ressource


// resources.qrc (Editer le fichier ressource)
...
<RCC>
  <qresource prefix="/img">
    <file alias="logo.png">data/img/logo.png</file>
  </qresource>
</RCC>
...

Exécution du projet


// Terminal (Exécuter le projet)
...
rdvcpp.exe
...

image.png

image.png

image.png


Démo de l'application


https://www.youtube.com/watch?v=zHWRMOeXmqQ


Gérer des configurations utilisateur en C++ sous Qt


Qt est une librairie de création d'interfaces homme machine prenant en charge la gestion des configurations utilisateur. QSettings peut être utilisé pour sauvegarder de manière permanente toutes les configurations utilisateur associées à une application. Dans ce tutoriel, nous utilisons QSettings pour sauvegarder les paramètres d'une application de gestion d'oscilloscope numérique.


Gestion du programme principal


// main.cpp (Editer le fichier source)
...
#include "cMainWindow.h"
#include <QApplication>

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    cMainWindow *oMainWindow = new cMainWindow;
    oMainWindow->resize(400, 500);
    oMainWindow->show();
    return app.exec();
}
...

Gestion de la fenêtre principale


// cMainWindow.h (Editer la fenêtre principale)
...
#pragma once

#include <QMainWindow>

class QLabel;
class QSettings;

namespace Ui
{
    class cMainWindow;
}

class cMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    struct sSettingsDTO
    {
        // General
        QString inputDevice;
        int bufferSize;
        int nanValue;
        bool isAfterGlow;
        int refreshRate;
        QString settingsPath;
        // Format
        QString displayFormat;
        QString binaryFormat;
        // Sacling
        double scalingA;
        double scalingB;
        bool isScalingEnabled;
    };

public:
    explicit cMainWindow(QWidget *parent = 0);
    ~cMainWindow();

private:
    void loadDefaultValue(sSettingsDTO &_settingsDTO);
    void readSettings(sSettingsDTO &_settingsDTO);
    void writeSettings(const sSettingsDTO &_settingsDTO);
    void saveSettings(QSettings &_settings, const sSettingsDTO &_settingsDTO);
    void loadSettings(QSettings &_settings, sSettingsDTO &_settingsDTO);

protected:
    void closeEvent(QCloseEvent *event);

private slots:
    void on_actionSaveSettings_triggered();
    void on_actionLoadSettings_triggered();
    void on_actionSettingsPage_triggered();
    void on_btnSettingsOK_clicked();

private:
    Ui::cMainWindow *ui;
    QString m_settingsPath;
};
...

// cMainWindow.cpp (Editer la fenêtre principale)
...
#include "cMainWindow.h"
#include "ui_cMainWindow.h"
#include <QFileDialog>
#include <QSettings>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>
#include <QCloseEvent>

// Organization
static const QString DEF_ORGANIZATION_NAME = "ReadyDEV";
static const QString DEF_APP_NAME = "ReadySCOPE";
// Settings : General
static const QString DEF_INPUT_DEVICE = "InputDevice";
static const QString DEF_BUFFER_SIZE = "BufferSize";
static const QString DEF_NAN_VALUE = "NanValue";
static const QString DEF_AFTER_GLOW = "AfterGlow";
static const QString DEF_REFRESH_RATE = "RefreshRate";
static const QString DEF_SETTINGS_PATH = "SettingsPath";
// Settings : Format
static const QString DEF_SETTINGS_FORMAT = "Format";
static const QString DEF_DISPLAY_FORMAT = "DisplayFormat";
static const QString DEF_BINARY_FORMAT = "BinaryFormat";
// Settings : Scaling
static const QString DEF_SETTINGS_SCALING = "Scaling";
static const QString DEF_SCALING_A = "ScalingA";
static const QString DEF_SCALING_B = "ScalingB";
static const QString DEF_SCALING_ENABLED = "ScalingEnabled";

cMainWindow::cMainWindow(QWidget *parent)
    : QMainWindow(parent),
      ui(new Ui::cMainWindow)
{
    ui->setupUi(this);
    ui->stackedWidget->setCurrentWidget(ui->pageHome);
    QSettings oSettings(DEF_ORGANIZATION_NAME, DEF_APP_NAME);
    sSettingsDTO oSettingsDTO;
    loadSettings(oSettings, oSettingsDTO);
    writeSettings(oSettingsDTO);
}

cMainWindow::~cMainWindow()
{
    delete ui;
}

void cMainWindow::loadDefaultValue(sSettingsDTO &_settingsDTO)
{
    // General
    _settingsDTO.inputDevice = "[input-device]";
    _settingsDTO.bufferSize = 100000;
    _settingsDTO.nanValue = 0;
    _settingsDTO.isAfterGlow = false;
    _settingsDTO.refreshRate = 10;
    _settingsDTO.settingsPath = QDir::homePath();
    // Format
    _settingsDTO.displayFormat = "[display-format]";
    _settingsDTO.binaryFormat = "[binary-format]";
    // Scaling
    _settingsDTO.scalingA = 1.0;
    _settingsDTO.scalingB = 0.0;
    _settingsDTO.isScalingEnabled = false;
}

void cMainWindow::readSettings(sSettingsDTO &_settingsDTO)
{
    // General
    _settingsDTO.inputDevice = ui->edtInputDevice->text();
    _settingsDTO.bufferSize = ui->edtBufferSize->value();
    _settingsDTO.nanValue = ui->edtNanValue->value();
    _settingsDTO.isAfterGlow = ui->radAfterGlowYes->isChecked();
    _settingsDTO.refreshRate = ui->edtRefreshRate->value();
    _settingsDTO.settingsPath = m_settingsPath;
    // Format
    _settingsDTO.displayFormat = ui->edtDisplayFormat->text();
    _settingsDTO.binaryFormat = ui->edtBinaryFormat->text();
    // Scaling
    _settingsDTO.scalingA = ui->edtScalingA->value();
    _settingsDTO.scalingB = ui->edtScalingB->value();
    _settingsDTO.isScalingEnabled = ui->chbScalingEnabled->isChecked();
}

void cMainWindow::writeSettings(const sSettingsDTO &_settingsDTO)
{
    // General
    ui->edtInputDevice->setText(_settingsDTO.inputDevice);
    ui->edtBufferSize->setValue(_settingsDTO.bufferSize);
    ui->edtNanValue->setValue(_settingsDTO.nanValue);
    ui->radAfterGlowYes->setChecked(_settingsDTO.isAfterGlow);
    ui->radAfterGlowNo->setChecked(!_settingsDTO.isAfterGlow);
    ui->edtRefreshRate->setValue(_settingsDTO.refreshRate);
    m_settingsPath = _settingsDTO.settingsPath;
    // Format
    ui->edtDisplayFormat->setText(_settingsDTO.displayFormat);
    ui->edtBinaryFormat->setText(_settingsDTO.binaryFormat);
    // Scaling
    ui->edtScalingA->setValue(_settingsDTO.scalingA);
    ui->edtScalingB->setValue(_settingsDTO.scalingB);
    ui->chbScalingEnabled->setChecked(_settingsDTO.isScalingEnabled);
}

void cMainWindow::saveSettings(QSettings &_settings, const sSettingsDTO &_settingsDTO)
{
    // General
    _settings.setValue(DEF_INPUT_DEVICE, _settingsDTO.inputDevice);
    _settings.setValue(DEF_BUFFER_SIZE, _settingsDTO.bufferSize);
    _settings.setValue(DEF_NAN_VALUE, _settingsDTO.nanValue);
    _settings.setValue(DEF_AFTER_GLOW, _settingsDTO.isAfterGlow);
    _settings.setValue(DEF_REFRESH_RATE, _settingsDTO.refreshRate);
    _settings.setValue(DEF_SETTINGS_PATH, _settingsDTO.settingsPath);
    // Format
    _settings.beginGroup(DEF_SETTINGS_FORMAT);
    _settings.setValue(DEF_DISPLAY_FORMAT, _settingsDTO.displayFormat);
    _settings.setValue(DEF_BINARY_FORMAT, _settingsDTO.binaryFormat);
    _settings.endGroup();
    // Scaling
    _settings.beginGroup(DEF_SETTINGS_SCALING);
    _settings.setValue(DEF_SCALING_A, _settingsDTO.scalingA);
    _settings.setValue(DEF_SCALING_B, _settingsDTO.scalingB);
    _settings.setValue(DEF_SCALING_ENABLED, _settingsDTO.isScalingEnabled);
    _settings.endGroup();
}

void cMainWindow::loadSettings(QSettings &_settings, sSettingsDTO &_settingsDTO)
{
    sSettingsDTO oSettingsDTO;
    loadDefaultValue(oSettingsDTO);

    // General
    _settingsDTO.inputDevice = _settings.value(DEF_INPUT_DEVICE, oSettingsDTO.inputDevice).toString();
    _settingsDTO.bufferSize = _settings.value(DEF_BUFFER_SIZE, oSettingsDTO.bufferSize).toInt();
    _settingsDTO.nanValue = _settings.value(DEF_NAN_VALUE, oSettingsDTO.nanValue).toInt();
    _settingsDTO.isAfterGlow = _settings.value(DEF_AFTER_GLOW, oSettingsDTO.isAfterGlow).toBool();
    _settingsDTO.refreshRate = _settings.value(DEF_REFRESH_RATE, oSettingsDTO.refreshRate).toInt();
    _settingsDTO.settingsPath = _settings.value(DEF_SETTINGS_PATH, oSettingsDTO.settingsPath).toString();
    // Format
    _settings.beginGroup(DEF_SETTINGS_FORMAT);
    _settingsDTO.displayFormat = _settings.value(DEF_DISPLAY_FORMAT, oSettingsDTO.displayFormat).toString();
    _settingsDTO.binaryFormat = _settings.value(DEF_BINARY_FORMAT, oSettingsDTO.binaryFormat).toString();
    _settings.endGroup();
    // Scaling
    _settings.beginGroup(DEF_SETTINGS_SCALING);
    _settingsDTO.scalingA = _settings.value(DEF_SCALING_A, oSettingsDTO.scalingA).toDouble();
    _settingsDTO.scalingB = _settings.value(DEF_SCALING_B, oSettingsDTO.scalingB).toDouble();
    _settingsDTO.isScalingEnabled = _settings.value(DEF_SCALING_ENABLED, oSettingsDTO.isScalingEnabled).toBool();
    _settings.endGroup();
}

void cMainWindow::closeEvent(QCloseEvent *event)
{
    sSettingsDTO oSettingsDTO;
    readSettings(oSettingsDTO);
    QSettings oSettings(DEF_ORGANIZATION_NAME, DEF_APP_NAME);
    saveSettings(oSettings, oSettingsDTO);
}

void cMainWindow::on_actionSaveSettings_triggered()
{

    QString oFilename = QFileDialog::getSaveFileName(this, tr("Sauvegarder les configurations"), m_settingsPath, tr("Settings (*.ini)"));
    if (oFilename.isEmpty())
    {
        qDebug() << "L'enregistrement des configurations a ete annule.";
        return;
    }

    m_settingsPath = QFileInfo(oFilename).absolutePath();

    sSettingsDTO oSettingsDTO;
    readSettings(oSettingsDTO);
    QSettings oSettings(oFilename, QSettings::IniFormat);
    saveSettings(oSettings, oSettingsDTO);

    qDebug() << "L'enregistrement des configurations s'est bien deroule."
             << "|filename=" << oFilename;
}

void cMainWindow::on_actionLoadSettings_triggered()
{
    QString oFilename = QFileDialog::getOpenFileName(this, tr("Charger les configurations"), m_settingsPath, tr("Settings (*.ini)"));
    if (oFilename.isEmpty())
    {
        qDebug() << "Le chargement des configurations a ete annule.";
        return;
    }

    m_settingsPath = QFileInfo(oFilename).absolutePath();

    sSettingsDTO oSettingsDTO;
    QSettings oSettings(oFilename, QSettings::IniFormat);
    loadSettings(oSettings, oSettingsDTO);
    writeSettings(oSettingsDTO);

    qDebug() << "Le chargement des configurations s'est bien deroule."
             << "|filename=" << oFilename;
}

void cMainWindow::on_actionSettingsPage_triggered()
{
    ui->stackedWidget->setCurrentWidget(ui->pageSettings);
}

void cMainWindow::on_btnSettingsOK_clicked()
{
    ui->stackedWidget->setCurrentWidget(ui->pageHome);
}
...

// cMainWindow.ui (Editer le menu général)
image.png

// cMainWindow.ui (Editer la fiche des configurations)
image.png

Gestion du fichier CMake


// CMakeLists.txt (Editer le fichier CMake)
...
cmake_minimum_required(VERSION 3.10.0)
project(rdvcpp VERSION 0.1.0 LANGUAGES C CXX)

set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_PREFIX_PATH "C:/Qt/6.5.2/msvc2019_64/lib/cmake")

find_package(Qt6 REQUIRED COMPONENTS
    Widgets
)

qt_wrap_ui(UI_FILES
    cMainWindow.ui
)

add_executable(rdvcpp
    main.cpp
    cMainWindow.cpp
    resources.qrc
    ${UI_FILES}
)

target_link_libraries (rdvcpp
    Qt6::Widgets
)
...

Gestion du fichier ressource


// resources.qrc (Editer le fichier ressource)
...
<RCC>
  <qresource prefix="/img">
    <file alias="logo.png">data/img/logo.png</file>
  </qresource>
</RCC>
...

Exécution du projet


// Terminal (Exécuter le projet)
...
rdvcpp.exe
...

// Application (Fiche du menu général)
image.png

// Application (Fiche des configurations)
image.png

// Application (Registre des configurations utilisateur sous Windows)
image.png

// Application (Registre des configurations utilisateur sous Windows)
image.png

// Application (Registre des configurations utilisateur sous Windows)
image.png

// Application (Sauvegarde des configuration dans un fichier)
image.png

Démo de l'application


https://www.youtube.com/watch?v=aHYklSnqhI0