ReadyDev
...
#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();
}
......
#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;
};
......
#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()));
}
}
......
#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;
};
......
#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);
}
}
......
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
)
......
<RCC>
<qresource prefix="/img">
<file alias="logo.png">data/img/logo.png</file>
</qresource>
</RCC>
...... rdvcpp.exe ...
...
#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();
}
......
#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;
};
......
#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);
}
......
#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;
};
......
#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());
}
......
#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;
};
......
#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;
}
......
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
)
......
<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>
...... rdvcpp.exe ...
...
#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();
}
......
#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;
};
......
#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();
}
}
......
#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;
};
......
#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);
}
......
#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;
};
......
#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;
}
......
#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;
};
......
#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;
}
......
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
)
......
<RCC>
<qresource prefix="/img">
<file alias="logo.png">data/img/logo.png</file>
</qresource>
</RCC>
...... rdvcpp.exe ...
...
#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();
}
......
#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;
};
......
#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);
}
......
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
)
......
<RCC>
<qresource prefix="/img">
<file alias="logo.png">data/img/logo.png</file>
</qresource>
</RCC>
...... rdvcpp.exe ...
...
#include "cMainWindow.h"
#include <QApplication>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
cMainWindow *oMainWindow = new cMainWindow;
oMainWindow->resize(640, 480);
oMainWindow->show();
return app.exec();
}
......
#pragma once
#include <QMainWindow>
#include "cPlot.h"
namespace Ui
{
class cMainWindow;
}
class cMainWindow : public QMainWindow
{
Q_OBJECT
public:
using sPlot = cPlot::sPlot;
using sPlots = cPlot::sPlots;
public:
explicit cMainWindow(QWidget *parent = 0);
~cMainWindow();
private:
void addManagePlot(const sPlot &_plot);
void updateManagePlot();
private slots:
void on_actionChangeBackgroundColor_triggered();
void on_actionAddPlot_triggered();
void on_actionPlotPage_triggered();
void on_actionManagePlotPage_triggered();
void on_plot_emitResizePlot();
protected:
void resizeEvent(QResizeEvent *event);
void timerEvent(QTimerEvent *event);
private:
Ui::cMainWindow *ui;
QVector<QImage> m_images;
int m_refreshTime;
int m_refreshTimerId;
};
......
#include "cMainWindow.h"
#include "ui_cMainWindow.h"
#include <QColorDialog>
#include <QResizeEvent>
#include <QMessageBox>
static const int DEF_REFRESH_TIME = 100; // 100ms : 10 Hz
cMainWindow::cMainWindow(QWidget *parent)
: QMainWindow(parent),
ui(new Ui::cMainWindow),
m_refreshTime(DEF_REFRESH_TIME)
{
ui->setupUi(this);
ui->stackedWidget->setCurrentWidget(ui->pagePlot);
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
m_refreshTimerId = startTimer(m_refreshTime);
}
cMainWindow::~cMainWindow()
{
delete ui;
}
void cMainWindow::addManagePlot(const sPlot &_plot)
{
ui->tableWidget->insertRow(ui->tableWidget->rowCount());
int iCol = 0;
QTableWidgetItem *oId = new QTableWidgetItem(QString("%1").arg(_plot.id));
QTableWidgetItem *oX = new QTableWidgetItem(QString("%1").arg(_plot.x));
QTableWidgetItem *oY = new QTableWidgetItem(QString("%1").arg(_plot.y));
QTableWidgetItem *oWidth = new QTableWidgetItem(QString("%1").arg(_plot.width));
QTableWidgetItem *oHeight = new QTableWidgetItem(QString("%1").arg(_plot.height));
QTableWidgetItem *oDivision = new QTableWidgetItem(QString("%1").arg(_plot.nDivision));
ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, iCol++, oId);
ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, iCol++, oX);
ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, iCol++, oY);
ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, iCol++, oWidth);
ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, iCol++, oHeight);
ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, iCol++, oDivision);
}
void cMainWindow::updateManagePlot()
{
if (ui->plot->getSize())
{
ui->tableWidget->setRowCount(0);
for (const auto &oPlot : ui->plot->getPlots())
{
addManagePlot(oPlot);
}
}
}
void cMainWindow::on_actionChangeBackgroundColor_triggered()
{
QColor oldColor = ui->plot->getBackgroundColor();
QColor newColor = QColorDialog::getColor(oldColor, this, tr("Sélectionner une couleur"));
if (!newColor.isValid())
{
qDebug() << "Aucune couleur n'a ete selectionne.";
return;
}
if (newColor != oldColor)
{
ui->plot->setBackgroundColor(newColor);
}
}
void cMainWindow::on_actionAddPlot_triggered()
{
if (ui->plot->isMax())
{
QMessageBox::critical(this, tr("Messages d'erreurs"),
tr("Le nombre maximal d'oscilloscopes est atteint."));
return;
}
ui->plot->addPlot();
updateManagePlot();
}
void cMainWindow::on_actionPlotPage_triggered()
{
ui->stackedWidget->setCurrentWidget(ui->pagePlot);
}
void cMainWindow::on_actionManagePlotPage_triggered()
{
ui->stackedWidget->setCurrentWidget(ui->pageManagePlot);
}
void cMainWindow::on_plot_emitResizePlot()
{
updateManagePlot();
}
void cMainWindow::resizeEvent(QResizeEvent *event)
{
QWidget *oCurrentWidget = ui->stackedWidget->currentWidget();
if (oCurrentWidget != ui->pagePlot)
{
ui->stackedWidget->setCurrentWidget(ui->pagePlot);
ui->stackedWidget->setCurrentWidget(oCurrentWidget);
}
}
void cMainWindow::timerEvent(QTimerEvent *event)
{
ui->plot->render();
ui->plot->repaint();
}
......
#pragma once
#include <QWidget>
#include <QImage>
#include <QVector>
#include <QMap>
class QMenu;
class cPlot : public QWidget
{
Q_OBJECT
public:
struct sPlot
{
int id;
int x;
int y;
int width;
int height;
int nDivision;
};
using sPlots = QVector<sPlot>;
using sData = QVector<QPointF>;
using sImages = QMap<int, QImage>;
using sDatas = QMap<int, sData>;
using sXShiftValues = QMap<int, double>;
using sAnimatePlots = QMap<int, bool>;
using sOffsets = QMap<int, QPointF>;
public:
explicit cPlot(QWidget *parent = nullptr);
~cPlot();
void render();
void setBackgroundColor(const QColor _color);
void addPlot();
bool isMax() const;
const QColor &getBackgroundColor() const { return m_backgroundColor; }
sPlots &getPlots() { return m_plots; }
const sPlots &getPlots() const { return m_plots; }
int getSize() const { return m_plots.size(); }
private:
void addPlotImage(int _plotId, int _width, int _height);
void addPlotXShiftValue(int _plotId);
void addPlotOffset(int _plotId);
//
void initScreenSize();
void createPlotMenu();
bool loadAllPlots(sPlots &_plots) const;
bool loadPlot(int _x, int _y, sPlot &_plot) const;
bool isActivePlot(const QPoint &_pos) const;
bool isActivePlot(const QPoint &_pos, int &_plotId) const;
bool hasPlotImage(int _plotId) const;
bool hasPlotData(int _plotId) const;
bool hasPlotXShiftValue(int _plotId) const;
bool hasPlotOffset(int _plotId) const;
bool isAnimatePlot(int _plotId) const;
void generatePlotData(sData &_datas, double _xShiftValue);
QPointF pointToPlot(const QPointF &_point) const;
void drawText(QPaintDevice *_image, int _x, int _y, int _width, int _height, int _fontSize, bool _isBold, const QColor &_color, int _align, const QString &_text);
//
void drawPlotBackgroundColor();
void drawPlotsBackgroundColor();
void drawPlotsDefaultBorder();
void drawPlotsBorder();
void drawTextNoPlots();
void drawActivePlots();
void drawPlotsGrids();
void drawPlotsGridsDivs();
void drawPlotsGridsTicks();
void drawPlotsGridsTicksDivs();
void drawPlotsGridsDivsValues();
void drawAnimatePlots();
void drawPlotsDatas();
void drawPlots();
protected:
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
void mousePressEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
private:
void onResizePlot(const QSize &_size);
void onPlotMenu(const QPoint &_pos);
void onAddPlotData();
void onAnimatePlotData();
void onPlotClick(const QPoint &_pos);
signals:
void emitResizePlot(QSize _size);
void emitPlotMenu(QPoint _pos);
void emitPlotClick(QPoint _pos);
private:
sPlots m_plots;
sImages m_images;
sDatas m_datas;
sXShiftValues m_xShiftValues;
sAnimatePlots m_isAnimatePlots;
sOffsets m_offsets;
//
QSize m_screenSize;
QImage m_image;
QMenu *m_plotMenu;
QColor m_backgroundColor;
//
double m_scaleFactor;
};
......
#include "cPlot.h"
#include "cMainWindow.h"
#include <QPainter>
#include <QPaintEvent>
#include <QMenu>
#include <QApplication>
#include <QScreen>
#include <QMessageBox>
// debug
static const bool DEF_DEBUG_ON = false;
// plot
static const int DEF_PLOT_MAX = 9;
static const int DEF_PLOT_MARGIN_LEFT = 70;
static const int DEF_PLOT_MARGIN_BOTTOM = 50;
static const int DEF_PLOT_MARGIN_TOP = 30;
static const int DEF_PLOT_MARGIN_RIGHT = 10;
static const int DEF_PLOT_PIXEL_PER_DIV = 40;
static const int DEF_PLOT_TEXT_FONT_SIZE = 10;
static const int DEF_PLOT_DATA_NUMBER = 1024;
static const double DEF_PLOT_X_MIN = -45;
static const double DEF_PLOT_X_MAX = 2000;
static const double DEF_PLOT_X_SHIT_VALUE = 45;
static const double DEF_PLOT_X_SHIT_PER_TIME = 5;
static const QPointF DEF_PLOT_OFFSET = QPointF(-5, -3);
static const double DEF_PLOT_X_PER_DIV = 90.0 / 2.0;
static const double DEF_PLOT_Y_PER_DIV = 1.0 / 2.0;
static const int DEF_PLOT_DEFAULT_BORDER_THICKNESS = 1;
static const int DEF_PLOT_BORDER_THICKNESS = 2;
static const int DEF_PLOT_DATA_THICKNESS = 2;
static const QColor DEF_PLOT_BACKGROUND_COLOR = "#FF000000";
static const QColor DEF_PLOT_DEFAULT_BORDER_COLOR = "#FF404040";
static const QColor DEF_PLOT_BORDER_COLOR = "#FFAA0000";
static const QColor DEF_PLOT_TEXT_COLOR = "#FFAA0000";
static const QColor DEF_NO_PLOT_TEXT_COLOR = "#FF808080";
static const QColor DEF_NO_PLOT_BACKGROUND_COLOR = "#80808080";
static const QColor DEF_PLOT_DATA_COLOR = "#FFAA00AA";
static const QString DEF_PLOT_FONT_FAMILY = "Arial";
static const QString DEF_NO_PLOT_TEXT = "[NO-PLOT]";
static const QString DEF_NO_PLOT_ITEM_TEXT = "NO-PLOT-[%1]";
static const QString DEF_PLOT_ITEM_TEXT = "PLOT-[%1]";
// axis
static const int DEF_AXIS_DIV_PER_GRID = 2;
static const int DEF_AXIS_THICKNESS = 2;
static const int DEF_AXIS_GRID_THICKNESS = 1;
static const int DEF_AXIS_TICK_THICKNESS = 1;
static const int DEF_AXIS_TICK_DIV_THICKNESS = 2;
static const int DEF_AXIS_DIV_PER_GRID_THICKNESS = 2;
static const int DEF_AXIS_TICK_SIZE = 5;
static const int DEF_AXIS_TICK_GRID_SIZE = 10;
static const int DEF_AXIS_DIV_VALUE_FONT_SIZE = 10;
static const double DEF_AXIS_TICK_PER_DIV = 5.0;
static const double DEF_AXIS_TICK_DIV_PER_GRID = 2.0;
static const QColor DEF_AXIS_COLOR = "#FF808080";
static const QColor DEF_AXIS_TICK_COLOR = "#FFAA0000";
static const QColor DEF_AXIS_TICK_VALUE_COLOR = "#FFAA0000";
static const QColor DEF_AXIS_GRID_COLOR = "#FF333333";
static const QColor DEF_AXIS_DIV_PER_GRID_COLOR = "#FF222222";
cPlot::cPlot(QWidget *parent)
: QWidget(parent),
m_image(parent->width(), parent->height(), QImage::Format_ARGB32),
m_scaleFactor(1.0),
m_backgroundColor(DEF_PLOT_BACKGROUND_COLOR)
{
initScreenSize();
createPlotMenu();
connect(this, &cPlot::emitResizePlot, this, &cPlot::onResizePlot);
connect(this, &cPlot::emitPlotMenu, this, &cPlot::onPlotMenu);
connect(this, &cPlot::emitPlotClick, this, &cPlot::onPlotClick);
}
cPlot::~cPlot()
{
}
void cPlot::render()
{
drawPlotBackgroundColor();
drawPlotsBackgroundColor();
drawPlotsDefaultBorder();
drawTextNoPlots();
drawActivePlots();
drawPlotsGrids();
drawPlotsGridsDivs();
drawPlotsGridsTicks();
drawPlotsGridsTicksDivs();
drawPlotsGridsDivsValues();
drawAnimatePlots();
drawPlotsDatas();
drawPlotsBorder();
drawPlots();
}
void cPlot::setBackgroundColor(const QColor _color)
{
if (m_backgroundColor != _color)
{
m_backgroundColor = _color;
}
}
void cPlot::addPlot()
{
if (isMax())
return;
m_plots.push_back(sPlot());
int oSzie = m_plots.size();
double oSqrt = sqrt((double)oSzie);
int oCeil = (int)ceil(oSqrt);
int oDivision = oCeil;
int oWidth = width() / oDivision;
int oHeight = height() / oDivision;
for (int iCount = 0; iCount < m_plots.size(); iCount++)
{
int oId = iCount;
int iX = iCount % oDivision;
int iY = iCount / oDivision;
int oX = iX * oWidth;
int oY = iY * oHeight;
sPlot &oPlot = m_plots[iCount];
oPlot.id = oId;
oPlot.x = oX;
oPlot.y = oY;
oPlot.width = oWidth;
oPlot.height = oHeight;
oPlot.nDivision = oDivision;
addPlotImage(oPlot.id, oWidth, oHeight);
addPlotXShiftValue(oPlot.id);
addPlotOffset(oPlot.id);
}
if (m_plots.size() && DEF_DEBUG_ON)
{
qDebug() << "\nLe calcul des parametres de l'oscillosocpe.";
for (const auto &oPlot : m_plots)
{
qDebug() << "|id=" << oPlot.id
<< "|x=" << oPlot.x
<< "|y=" << oPlot.y
<< "|width=" << oPlot.width
<< "|height=" << oPlot.height
<< "|WIDTH=" << width()
<< "|HEIGHT=" << height()
<< "|nSCOPE=" << oPlot.nDivision * oPlot.nDivision;
}
}
}
bool cPlot::isMax() const
{
return (m_plots.size() >= DEF_PLOT_MAX);
}
void cPlot::addPlotImage(int _plotId, int _width, int _height)
{
if (hasPlotImage(_plotId))
{
QImage &oImage = m_images[_plotId];
oImage = oImage.scaled(QSize(_width, _height) * m_scaleFactor);
}
else
{
m_images[_plotId] = QImage(QSize(_width, _height) * m_scaleFactor, QImage::Format_ARGB32);
}
}
void cPlot::addPlotXShiftValue(int _plotId)
{
if (!hasPlotXShiftValue(_plotId))
{
m_xShiftValues[_plotId] = _plotId * DEF_PLOT_X_SHIT_VALUE;
}
}
void cPlot::addPlotOffset(int _plotId)
{
if (!hasPlotOffset(_plotId))
{
m_offsets[_plotId] = DEF_PLOT_OFFSET;
}
}
void cPlot::initScreenSize()
{
m_screenSize = QApplication::primaryScreen()->geometry().size();
qDebug() << Q_FUNC_INFO
<< "|screenSize=" << m_screenSize;
}
void cPlot::createPlotMenu()
{
m_plotMenu = new QMenu(this);
QAction *oAction;
oAction = new QAction("Ajouter des données");
connect(oAction, &QAction::triggered, this, &cPlot::onAddPlotData);
m_plotMenu->addAction(oAction);
oAction = new QAction("Animer les données");
connect(oAction, &QAction::triggered, this, &cPlot::onAnimatePlotData);
m_plotMenu->addAction(oAction);
}
bool cPlot::loadAllPlots(sPlots &_plots) const
{
if (m_plots.isEmpty())
return false;
const sPlot &oPlot = m_plots[0];
int oDivision = oPlot.nDivision;
int oWidth = oPlot.width;
int oHeight = oPlot.height;
int oSize = oDivision * oDivision;
for (int iCount = 0; iCount < oSize; iCount++)
{
int oId = iCount;
int iX = iCount % oDivision;
int iY = iCount / oDivision;
int oX = iX * oWidth;
int oY = iY * oHeight;
sPlot iPlot;
iPlot.id = oId;
iPlot.x = oX;
iPlot.y = oY;
iPlot.width = oWidth;
iPlot.height = oHeight;
iPlot.nDivision = oDivision;
_plots.push_back(iPlot);
}
if (_plots.size() && DEF_DEBUG_ON)
{
qDebug() << "\nLe calcul des parametres de l'oscillosocpe [par défaut].";
for (const auto &iPlot : _plots)
{
qDebug() << "|id=" << iPlot.id
<< "|x=" << iPlot.x
<< "|y=" << iPlot.y
<< "|width=" << iPlot.width
<< "|height=" << iPlot.height
<< "|WIDTH=" << width()
<< "|HEIGHT=" << height()
<< "|nSCOPE=" << iPlot.nDivision * iPlot.nDivision;
}
}
return true;
}
bool cPlot::loadPlot(int _x, int _y, sPlot &_plot) const
{
if (m_plots.size())
{
sPlots oPlots;
if (loadAllPlots(oPlots))
{
for (const auto &oPlot : oPlots)
{
QRegion oRegion(oPlot.x, oPlot.y, oPlot.width, oPlot.height);
if (oRegion.contains(QPoint(_x, _y)))
{
_plot = oPlot;
return true;
}
}
}
}
return false;
}
bool cPlot::isActivePlot(const QPoint &_pos) const
{
for (const auto &oPlot : m_plots)
{
QRegion oRegion(oPlot.x, oPlot.y, oPlot.width, oPlot.height);
if (oRegion.contains(_pos))
{
return true;
}
}
return false;
}
bool cPlot::isActivePlot(const QPoint &_pos, int &_plotId) const
{
for (const auto &oPlot : m_plots)
{
QRegion oRegion(oPlot.x, oPlot.y, oPlot.width, oPlot.height);
if (oRegion.contains(_pos))
{
_plotId = oPlot.id;
return true;
}
}
return false;
}
bool cPlot::hasPlotImage(int _plotId) const
{
for (const auto &oPlotId : m_images.keys())
{
if (oPlotId == _plotId)
{
return true;
}
}
return false;
}
bool cPlot::hasPlotData(int _plotId) const
{
for (const auto &oPlotId : m_datas.keys())
{
if (oPlotId == _plotId)
{
return true;
}
}
return false;
}
bool cPlot::hasPlotXShiftValue(int _plotId) const
{
for (const auto &oPlotId : m_xShiftValues.keys())
{
if (oPlotId == _plotId)
{
return true;
}
}
return false;
}
bool cPlot::hasPlotOffset(int _plotId) const
{
for (const auto &oPlotId : m_offsets.keys())
{
if (oPlotId == _plotId)
{
return true;
}
}
return false;
}
bool cPlot::isAnimatePlot(int _plotId) const
{
for (const auto &oPlotId : m_isAnimatePlots.keys())
{
if (oPlotId == _plotId)
{
return true;
}
}
return false;
}
void cPlot::generatePlotData(sData &_datas, double _xShiftValue)
{
for (int iX = 0; iX < DEF_PLOT_DATA_NUMBER; iX++)
{
double oX = DEF_PLOT_X_MIN + ((DEF_PLOT_X_MAX - DEF_PLOT_X_MIN) * iX) / DEF_PLOT_DATA_NUMBER;
double oY = 2 + qSin(qDegreesToRadians(oX));
oX = oX - _xShiftValue;
QPointF oData(oX, oY);
_datas.push_back(oData);
}
}
QPointF cPlot::pointToPlot(const QPointF &_point) const
{
double oX = _point.x() * DEF_PLOT_PIXEL_PER_DIV / DEF_PLOT_X_PER_DIV;
double oY = _point.y() * DEF_PLOT_PIXEL_PER_DIV / DEF_PLOT_Y_PER_DIV;
return QPointF(oX, oY);
}
void cPlot::drawText(QPaintDevice *_image, int _x, int _y, int _width, int _height, int _fontSize, bool _isBold, const QColor &_color, int _align, const QString &_text)
{
QPainter oPainter;
oPainter.begin(_image);
oPainter.setRenderHint(QPainter::TextAntialiasing);
oPainter.setPen(_color);
QFont oFont = oPainter.font();
oFont.setPointSize(_fontSize);
oFont.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
oFont.setBold(_isBold);
oFont.setFamily(DEF_PLOT_FONT_FAMILY);
oPainter.setFont(oFont);
oPainter.drawText(QRect(_x, _y, _width, _height), _align, _text);
oPainter.end();
}
void cPlot::drawPlotBackgroundColor()
{
QPainter oPainter;
oPainter.begin(&m_image);
oPainter.fillRect(0, 0, m_image.width(), m_image.height(), m_backgroundColor);
oPainter.end();
}
void cPlot::drawPlotsBackgroundColor()
{
for (sPlot &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.fillRect(0, 0, oPlot.width, oPlot.height, m_backgroundColor);
oPainter.end();
}
}
}
void cPlot::drawPlotsDefaultBorder()
{
sPlots oPlots;
if (loadAllPlots(oPlots))
{
for (int iCount = 0; iCount < oPlots.size(); iCount++)
{
if (iCount < m_plots.size())
{
sPlot &oPlot = m_plots[iCount];
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setPen(QPen(DEF_PLOT_DEFAULT_BORDER_COLOR, DEF_PLOT_DEFAULT_BORDER_THICKNESS, Qt::DashLine));
oPainter.drawRect(0, 0, oPlot.width, oPlot.height);
oPainter.end();
}
}
else
{
sPlot &oPlot = oPlots[iCount];
QPainter oPainter;
oPainter.begin(&m_image);
oPainter.setPen(QPen(DEF_PLOT_DEFAULT_BORDER_COLOR, DEF_PLOT_DEFAULT_BORDER_THICKNESS, Qt::DashLine));
oPainter.drawRect(oPlot.x, oPlot.y, oPlot.width, oPlot.height);
oPainter.end();
}
}
}
}
void cPlot::drawPlotsBorder()
{
for (auto &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
int oX = DEF_PLOT_MARGIN_LEFT;
int oY = DEF_PLOT_MARGIN_TOP;
int oWidth = oPlot.width - (DEF_PLOT_MARGIN_LEFT + DEF_PLOT_MARGIN_RIGHT);
int oHeight = oPlot.height - (DEF_PLOT_MARGIN_TOP + DEF_PLOT_MARGIN_BOTTOM);
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setPen(QPen(DEF_PLOT_BORDER_COLOR, DEF_PLOT_BORDER_THICKNESS));
oPainter.drawRect(oX, oY, oWidth, oHeight);
oPainter.end();
}
}
}
void cPlot::drawTextNoPlots()
{
if (m_plots.isEmpty())
{
drawText(&m_image, 0, 0, width(), height(), DEF_PLOT_TEXT_FONT_SIZE, false,
DEF_NO_PLOT_TEXT_COLOR, Qt::AlignCenter, DEF_NO_PLOT_TEXT);
return;
}
sPlots oPlots;
if (loadAllPlots(oPlots))
{
for (int iCount = 0; iCount < oPlots.size(); iCount++)
{
QString oText;
if (iCount < m_plots.size())
{
sPlot &oPlot = m_plots[iCount];
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
oText = QString(DEF_PLOT_ITEM_TEXT).arg(oPlot.id);
drawText(&oImage, 0, 0, oPlot.width, DEF_PLOT_MARGIN_TOP, DEF_PLOT_TEXT_FONT_SIZE, false,
DEF_PLOT_TEXT_COLOR, Qt::AlignCenter, oText);
}
}
else
{
sPlot &oPlot = oPlots[iCount];
oText = QString(DEF_NO_PLOT_ITEM_TEXT).arg(oPlot.id);
drawText(&m_image, oPlot.x, oPlot.y, oPlot.width, oPlot.height, DEF_PLOT_TEXT_FONT_SIZE, false,
DEF_NO_PLOT_TEXT_COLOR, Qt::AlignCenter, oText);
}
}
}
}
void cPlot::drawActivePlots()
{
if (m_plots.size())
{
QRegion oRegion(0, 0, width(), height());
for (const auto &oPlot : m_plots)
{
QRegion iRegion(oPlot.x, oPlot.y, oPlot.width, oPlot.height);
oRegion = oRegion.subtracted(iRegion);
}
QPainter oPainter;
oPainter.begin(&m_image);
oPainter.setClipRegion(oRegion);
oPainter.fillRect(0, 0, width(), height(), DEF_NO_PLOT_BACKGROUND_COLOR);
oPainter.end();
}
}
void cPlot::drawPlotsGrids()
{
for (auto &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
const double &xShiftValue = m_xShiftValues[oPlot.id];
int oXmax = oPlot.width - (DEF_PLOT_MARGIN_LEFT + DEF_PLOT_MARGIN_RIGHT);
int oYmax = oPlot.height - (DEF_PLOT_MARGIN_TOP + DEF_PLOT_MARGIN_BOTTOM);
QRect oRect(DEF_PLOT_MARGIN_LEFT, DEF_PLOT_MARGIN_TOP, oXmax, oYmax);
for (int iX = 0; iX < 3 * oXmax; iX += DEF_PLOT_PIXEL_PER_DIV)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
int oDx = iX - xShiftValue;
oPainter.setPen(QPen(DEF_AXIS_GRID_COLOR, DEF_AXIS_GRID_THICKNESS, Qt::DotLine));
oPainter.drawLine(oDx, 0, oDx, oYmax);
oPainter.end();
}
for (int iY = 0; iY < oYmax; iY += DEF_PLOT_PIXEL_PER_DIV)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
oPainter.setPen(QPen(DEF_AXIS_GRID_COLOR, DEF_AXIS_GRID_THICKNESS, Qt::DotLine));
oPainter.drawLine(0, iY, oXmax, iY);
oPainter.end();
}
}
}
}
void cPlot::drawPlotsGridsDivs()
{
for (auto &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
const double &xShiftValue = m_xShiftValues[oPlot.id];
int oXmax = oPlot.width - (DEF_PLOT_MARGIN_LEFT + DEF_PLOT_MARGIN_RIGHT);
int oYmax = oPlot.height - (DEF_PLOT_MARGIN_TOP + DEF_PLOT_MARGIN_BOTTOM);
QRect oRect(DEF_PLOT_MARGIN_LEFT, DEF_PLOT_MARGIN_TOP, oXmax, oYmax);
int oDiv = DEF_AXIS_DIV_PER_GRID * DEF_PLOT_PIXEL_PER_DIV;
for (int iX = 0; iX < 3 * oXmax; iX += oDiv)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
int oDx = iX - xShiftValue;
oPainter.setPen(QPen(DEF_AXIS_DIV_PER_GRID_COLOR, DEF_AXIS_DIV_PER_GRID_THICKNESS));
oPainter.drawLine(oDx, 0, oDx, oYmax);
oPainter.end();
}
for (int iY = 0; iY < oYmax; iY += oDiv)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
oPainter.setPen(QPen(DEF_AXIS_DIV_PER_GRID_COLOR, DEF_AXIS_DIV_PER_GRID_THICKNESS));
oPainter.drawLine(0, iY, oXmax, iY);
oPainter.end();
}
}
}
}
void cPlot::drawPlotsGridsTicks()
{
for (auto &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
const double &xShiftValue = m_xShiftValues[oPlot.id];
int oXmax = oPlot.width - (DEF_PLOT_MARGIN_LEFT + DEF_PLOT_MARGIN_RIGHT);
int oYmax = oPlot.height - (DEF_PLOT_MARGIN_TOP + DEF_PLOT_MARGIN_BOTTOM);
QRect oRect(DEF_PLOT_MARGIN_LEFT, DEF_PLOT_MARGIN_TOP, oXmax, oYmax);
int oTick = DEF_PLOT_PIXEL_PER_DIV / DEF_AXIS_TICK_PER_DIV;
for (int iX = 0; iX < 3 * oXmax; iX += oTick)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
int oDx = iX - xShiftValue;
oPainter.setPen(QPen(DEF_AXIS_TICK_COLOR, DEF_AXIS_TICK_THICKNESS, Qt::SolidLine));
oPainter.drawLine(oDx, -DEF_AXIS_TICK_SIZE, oDx, DEF_AXIS_TICK_SIZE);
oPainter.end();
}
for (int iY = 0; iY < oYmax; iY += oTick)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
oPainter.setPen(QPen(DEF_AXIS_TICK_COLOR, DEF_AXIS_TICK_THICKNESS, Qt::SolidLine));
oPainter.drawLine(-DEF_AXIS_TICK_SIZE, iY, DEF_AXIS_TICK_SIZE, iY);
oPainter.end();
}
}
}
}
void cPlot::drawPlotsGridsTicksDivs()
{
for (auto &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
const double &xShiftValue = m_xShiftValues[oPlot.id];
int oXmax = oPlot.width - (DEF_PLOT_MARGIN_LEFT + DEF_PLOT_MARGIN_RIGHT);
int oYmax = oPlot.height - (DEF_PLOT_MARGIN_TOP + DEF_PLOT_MARGIN_BOTTOM);
QRect oRect(DEF_PLOT_MARGIN_LEFT, DEF_PLOT_MARGIN_TOP, oXmax, oYmax);
int oDiv = DEF_PLOT_PIXEL_PER_DIV * DEF_AXIS_TICK_DIV_PER_GRID;
for (int iX = 0; iX < 3 * oXmax; iX += oDiv)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
int oDx = iX - xShiftValue;
oPainter.setPen(QPen(DEF_AXIS_TICK_COLOR, DEF_AXIS_TICK_DIV_THICKNESS, Qt::SolidLine));
oPainter.drawLine(oDx, -DEF_AXIS_TICK_GRID_SIZE, oDx, DEF_AXIS_TICK_GRID_SIZE);
oPainter.end();
}
oDiv = DEF_PLOT_PIXEL_PER_DIV;
for (int iY = 0; iY < oYmax; iY += oDiv)
{
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
oPainter.setPen(QPen(DEF_AXIS_TICK_COLOR, DEF_AXIS_TICK_DIV_THICKNESS, Qt::SolidLine));
oPainter.drawLine(-DEF_AXIS_TICK_GRID_SIZE, iY, DEF_AXIS_TICK_GRID_SIZE, iY);
oPainter.end();
}
}
}
}
void cPlot::drawPlotsGridsDivsValues()
{
for (auto &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
const double &xShiftValue = m_xShiftValues[oPlot.id];
int oXmax = oPlot.width - (DEF_PLOT_MARGIN_LEFT + DEF_PLOT_MARGIN_RIGHT);
int oYmax = oPlot.height - (DEF_PLOT_MARGIN_TOP + DEF_PLOT_MARGIN_BOTTOM);
QRect oRect(DEF_PLOT_MARGIN_LEFT, DEF_PLOT_MARGIN_TOP, oXmax, oYmax);
QRect oRect2(DEF_PLOT_MARGIN_LEFT - 10, DEF_PLOT_MARGIN_TOP, oXmax + DEF_PLOT_MARGIN_RIGHT, oYmax + DEF_PLOT_MARGIN_BOTTOM);
int oDiv = DEF_PLOT_PIXEL_PER_DIV * DEF_AXIS_TICK_DIV_PER_GRID;
for (int iX = 0; iX < 3 * oXmax; iX += oDiv)
{
double oX = iX * DEF_PLOT_X_PER_DIV / DEF_PLOT_PIXEL_PER_DIV;
QString oValue = QString("%1").arg(oX);
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect2);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, 1.0);
oPainter.setPen(DEF_AXIS_TICK_VALUE_COLOR);
int oDx = iX - xShiftValue;
QFont oFont = oPainter.font();
oFont.setPointSize(DEF_AXIS_DIV_VALUE_FONT_SIZE);
oFont.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
oFont.setFamily(DEF_PLOT_FONT_FAMILY);
oPainter.setFont(oFont);
oPainter.drawText(oDx - 40, 10, 80, 25, Qt::AlignHCenter | Qt::AlignTop, oValue);
oPainter.end();
}
oDiv = DEF_PLOT_PIXEL_PER_DIV;
for (int iY = 0; iY < oYmax; iY += oDiv)
{
double oY = iY * DEF_PLOT_Y_PER_DIV / DEF_PLOT_PIXEL_PER_DIV;
QString oValue = QString("%1").arg(oY);
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, 1.0);
oPainter.setPen(DEF_AXIS_TICK_VALUE_COLOR);
QFont oFont = oPainter.font();
oFont.setPointSize(DEF_AXIS_DIV_VALUE_FONT_SIZE);
oFont.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
oFont.setFamily(DEF_PLOT_FONT_FAMILY);
oPainter.setFont(oFont);
oPainter.drawText(-80 - 15, -iY - 20, 80, 40, Qt::AlignVCenter | Qt::AlignRight, oValue);
oPainter.end();
}
}
}
}
void cPlot::drawAnimatePlots()
{
for (const auto &oPlotId : m_isAnimatePlots.keys())
{
const bool &isAnimatePlot = m_isAnimatePlots[oPlotId];
if (hasPlotXShiftValue(oPlotId) && isAnimatePlot)
{
sData oData;
double &xShiftValues = m_xShiftValues[oPlotId];
xShiftValues += DEF_PLOT_X_SHIT_PER_TIME;
generatePlotData(oData, xShiftValues);
m_datas[oPlotId] = oData;
}
}
}
void cPlot::drawPlotsDatas()
{
for (const auto &oPlotId : m_datas.keys())
{
const sData &oDatas = m_datas[oPlotId];
const sPlot &oPlot = m_plots[oPlotId];
QImage &oImage = m_images[oPlot.id];
int oXmax = oPlot.width - (DEF_PLOT_MARGIN_LEFT + DEF_PLOT_MARGIN_RIGHT);
int oYmax = oPlot.height - (DEF_PLOT_MARGIN_TOP + DEF_PLOT_MARGIN_BOTTOM);
QRect oRect(DEF_PLOT_MARGIN_LEFT, DEF_PLOT_MARGIN_TOP, oXmax, oYmax);
for (int iX = 0; iX < oDatas.size() - 1; iX++)
{
QPointF oPoint1 = pointToPlot(oDatas[iX]);
QPointF oPoint2 = pointToPlot(oDatas[iX + 1]);
QPainter oPainter;
oPainter.begin(&oImage);
oPainter.setClipRect(oRect);
oPainter.translate(oRect.bottomLeft());
oPainter.scale(1.0, -1.0);
oPainter.setPen(QPen(DEF_PLOT_DATA_COLOR, DEF_PLOT_DATA_THICKNESS, Qt::SolidLine));
oPainter.drawLine(oPoint1, oPoint2);
oPainter.end();
}
}
}
void cPlot::drawPlots()
{
for (auto &oPlot : m_plots)
{
if (hasPlotImage(oPlot.id))
{
QImage &oImage = m_images[oPlot.id];
QPainter oPainter;
oPainter.begin(&m_image);
oPainter.drawImage(oPlot.x, oPlot.y, oImage.scaled(QSize(oPlot.width, oPlot.height) * m_scaleFactor));
oPainter.end();
}
}
}
void cPlot::paintEvent(QPaintEvent *event)
{
QPainter oPainter(this);
QRect oRect = rect() & event->rect();
oPainter.setClipRect(oRect);
oPainter.drawImage(0, 0, m_image.scaled(size() * m_scaleFactor));
}
void cPlot::resizeEvent(QResizeEvent *event)
{
m_image = m_image.scaled(event->size() * m_scaleFactor);
emit emitResizePlot(event->size());
}
void cPlot::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
emit emitPlotClick(event->pos());
}
else if (event->button() == Qt::RightButton)
{
emit emitPlotMenu(event->pos());
}
}
void cPlot::wheelEvent(QWheelEvent *event)
{
qDebug() << "cPlot::wheelEvent()...";
}
void cPlot::onResizePlot(const QSize &_size)
{
if (m_plots.size())
{
const sPlot &oPlot = m_plots[0];
int oDivision = oPlot.nDivision;
int oWidth = _size.width() / oDivision;
int oHeight = _size.height() / oDivision;
for (int iCount = 0; iCount < m_plots.size(); iCount++)
{
sPlot &iPlot = m_plots[iCount];
int oId = iCount;
int iX = iCount % oDivision;
int iY = iCount / oDivision;
int oX = iX * oWidth;
int oY = iY * oHeight;
iPlot.id = oId;
iPlot.x = oX;
iPlot.y = oY;
iPlot.width = oWidth;
iPlot.height = oHeight;
iPlot.nDivision = oDivision;
if (hasPlotImage(iPlot.id))
{
QImage &oImage = m_images[iPlot.id];
oImage = oImage.scaled(QSize(oWidth, oHeight) * m_scaleFactor);
}
}
}
if (m_plots.size() && DEF_DEBUG_ON)
{
qDebug() << "\nLe calcul des parametres de l'oscillosocpe.";
for (const auto &oPlot : m_plots)
{
qDebug() << "|id=" << oPlot.id
<< "|x=" << oPlot.x
<< "|y=" << oPlot.y
<< "|width=" << oPlot.width
<< "|height=" << oPlot.height
<< "|WIDTH=" << _size.width()
<< "|HEIGHT=" << _size.height()
<< "|nSCOPE=" << oPlot.nDivision * oPlot.nDivision;
}
}
}
void cPlot::onPlotMenu(const QPoint &_pos)
{
if (isActivePlot(_pos))
{
m_plotMenu->exec(mapToGlobal(_pos));
}
}
void cPlot::onAddPlotData()
{
QPoint oPos = mapFromGlobal(m_plotMenu->pos());
int oPlotId;
if (isActivePlot(oPos, oPlotId))
{
if (hasPlotData(oPlotId))
{
QMessageBox::critical(this, tr("Messages d'erreurs"),
tr("L'oscilloscope [%1] contient déjà des données.").arg(oPlotId));
return;
}
if (hasPlotXShiftValue(oPlotId))
{
sData oData;
const double &oXShiftValues = m_xShiftValues[oPlotId];
generatePlotData(oData, oXShiftValues);
m_datas[oPlotId] = oData;
}
}
}
void cPlot::onAnimatePlotData()
{
QPoint oPos = mapFromGlobal(m_plotMenu->pos());
int oPlotId;
if (isActivePlot(oPos, oPlotId))
{
if (!hasPlotData(oPlotId))
{
QMessageBox::critical(this, tr("Messages d'erreurs"),
tr("L'oscilloscope [%1] doit contenir des données.").arg(oPlotId));
return;
}
if (isAnimatePlot(oPlotId))
{
bool &isAnimatePlot = m_isAnimatePlots[oPlotId];
isAnimatePlot = !isAnimatePlot;
}
else
{
m_isAnimatePlots[oPlotId] = true;
}
}
}
void cPlot::onPlotClick(const QPoint &_pos)
{
sPlot oPlot;
if (loadPlot(_pos.x(), _pos.y(), oPlot))
{
qDebug() << "cPlot::mousePressEvent()...\n"
<< "|x=" << _pos.x()
<< "|y=" << _pos.y()
<< "|oPlot.id=" << oPlot.id
<< "|oPlot.x=" << oPlot.x
<< "|oPlot.y=" << oPlot.y
<< "|oPlot.width=" << oPlot.width
<< "|oPlot.height=" << oPlot.height
<< "|m_image.bytesPerLine=" << m_image.bytesPerLine()
<< "|m_image.width=" << m_image.width()
<< "|m_image.bits=" << m_image.bits()
<< "|m_image.bits=" << m_image.depth();
}
}
......
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
cPlot.cpp
resources.qrc
${UI_FILES}
)
target_link_libraries (rdvcpp
Qt6::Widgets
)
......
<RCC>
<qresource prefix="/img">
<file alias="logo.png">data/img/logo.png</file>
</qresource>
</RCC>
...... rdvcpp.exe ...