1 Star 0 Fork 119

giteezhangj/QtSerialPortPlotter

forked from 觉皇/QtSerialPortPlotter 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
mainwindow.cpp 37.55 KB
一键复制 编辑 原始数据 按行查看 历史
觉皇 提交于 2022-03-29 08:41 . 修复编译警告信息
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
/***************************************************************************
** This file is part of Serial Port Plotter **
** **
** **
** Serial Port Plotter is a program for plotting integer data from **
** serial port using Qt and QCustomPlot **
** **
** This program is free software: you can redistribute it and/or modify **
** it under the terms of the GNU General Public License as published by **
** the Free Software Foundation, either version 3 of the License, or **
** (at your option) any later version. **
** **
** This program is distributed in the hope that it will be useful, **
** but WITHOUT ANY WARRANTY; without even the implied warranty of **
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
** GNU General Public License for more details. **
** **
** You should have received a copy of the GNU General Public License **
** along with this program. If not, see http://www.gnu.org/licenses/. **
** **
****************************************************************************
** Author: Borislav **
** Contact: b.kereziev@gmail.com **
** Date: 29.12.14 **
****************************************************************************/
#include "mainwindow.hpp"
#include "ui_mainwindow.h"
#include <x86intrin.h>
/**
* @brief Constructor
* @param parent
*/
MainWindow::MainWindow (QWidget *parent) :
QMainWindow (parent),
ui (new Ui::MainWindow),
/* Populate colors */
line_colors{
/* For channel data (gruvbox palette) */
/* Light */
QColor ("#fb4934"),
QColor ("#b8bb26"),
QColor ("#fabd2f"),
QColor ("#83a598"),
QColor ("#d3869b"),
QColor ("#8ec07c"),
QColor ("#fe8019"),
/* Light */
QColor ("#cc241d"),
QColor ("#98971a"),
QColor ("#d79921"),
QColor ("#458588"),
QColor ("#b16286"),
QColor ("#689d6a"),
QColor ("#d65d0e"),
},
gui_colors {
#if 0
/* Monochromatic for axes and ui */
QColor (48, 47, 47, 255), /**< 0: qdark ui dark/background color */
QColor (80, 80, 80, 255), /**< 1: qdark ui medium/grid color */
QColor (170, 170, 170, 255), /**< 2: qdark ui light/text color */
QColor (48, 47, 47, 200) /**< 3: qdark ui dark/background color w/transparency */
#else
/* Monochromatic for axes and ui */
QColor (255, 255, 255, 255), /**< 0: qdark ui dark/background color */
QColor (175, 175, 175, 255), /**< 1: qdark ui medium/grid color */
QColor (85, 85, 85, 255), /**< 2: qdark ui light/text color */
QColor (207, 208, 208, 200) /**< 3: qdark ui dark/background color w/transparency */
#endif
},
/* Main vars */
connected (false),
plotting (false),
dataPointNumber (0),
channels(0),
serialPort (nullptr),
STATE (WAIT_START),
NUMBER_OF_POINTS (500)
{
ui->setupUi (this);
/* Init UI and populate UI controls */
createUI();
/* Setup plot area and connect controls slots */
setupPlot();
/* Wheel over plot when plotting */
connect (ui->plot, SIGNAL (mouseWheel (QWheelEvent*)), this, SLOT (onMouseWheelInPlot(QWheelEvent*)));
/* Slot for printing coordinates */
connect (ui->plot, SIGNAL (mouseMove (QMouseEvent*)), this, SLOT (onMouseMoveInPlot (QMouseEvent*)));
/* Channel selection */
connect (ui->plot, SIGNAL(selectionChangedByUser()), this, SLOT(channel_selection()));
connect (ui->plot, SIGNAL(legendDoubleClick (QCPLegend*, QCPAbstractLegendItem*, QMouseEvent*)), this, SLOT(legend_double_click (QCPLegend*, QCPAbstractLegendItem*, QMouseEvent*)));
/* Connect update timer to replot slot */
connect (&updateTimer, SIGNAL (timeout()), this, SLOT (replot()));
m_csvFile = nullptr;
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Destructor
*/
MainWindow::~MainWindow()
{
closeCsvFile();
if (serialPort != nullptr)
{
delete serialPort;
}
/* Save configs */
QSettings settings("config.ini", QSettings::IniFormat);
settings.setValue("com", ui->comboPort->currentText());
settings.setValue("baudrate", ui->comboBaud->currentText());
settings.setValue("databits", ui->comboData->currentIndex());
settings.setValue("stopbits", ui->comboStop->currentIndex());
settings.setValue("paritybits", ui->comboParity->currentIndex());
delete ui;
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Create remaining elements and populate the controls
*/
void MainWindow::createUI()
{
/* Check if there are any ports at all; if not, disable controls and return */
if (QSerialPortInfo::availablePorts().size() == 0)
{
enable_com_controls (false);
ui->statusBar->showMessage ("无可用端口!");
return;
}
/* List all available serial ports and populate ports combo box */
for (QSerialPortInfo port : QSerialPortInfo::availablePorts())
{
ui->comboPort->addItem (port.portName());
}
/* Populate baud rate combo box with standard rates */
ui->comboBaud->addItem ("1200");
ui->comboBaud->addItem ("2400");
ui->comboBaud->addItem ("4800");
ui->comboBaud->addItem ("9600");
ui->comboBaud->addItem ("19200");
ui->comboBaud->addItem ("38400");
ui->comboBaud->addItem ("57600");
ui->comboBaud->addItem ("115200");
/* And some not-so-standard */
ui->comboBaud->addItem ("128000");
ui->comboBaud->addItem ("153600");
ui->comboBaud->addItem ("230400");
ui->comboBaud->addItem ("256000");
ui->comboBaud->addItem ("460800");
ui->comboBaud->addItem ("921600");
/* Select 115200 bits by default */
ui->comboBaud->setCurrentIndex (7);
/* Populate data bits combo box */
ui->comboData->addItem ("8位");
ui->comboData->addItem ("7位");
/* Populate parity combo box */
ui->comboParity->addItem ("无校验");
ui->comboParity->addItem ("奇校验");
ui->comboParity->addItem ("偶校验");
/* Populate stop bits combo box */
ui->comboStop->addItem ("1位");
ui->comboStop->addItem ("2位");
/* Initialize the listwidget */
ui->listWidget_Channels->clear();
ui->comboPort->installEventFilter(this);
QFile file("config.ini");
if(!file.exists())
{
QSettings settings("config.ini", QSettings::IniFormat);
settings.setValue("com", "");
settings.setValue("baudrate", 115200);
settings.setValue("databits", 0);
settings.setValue("stopbits", 0);
settings.setValue("paritybits", 0);
settings.setValue("theme", "light");
}
QSettings settings("config.ini", QSettings::IniFormat);
int index = ui->comboPort->findText(settings.value("com").toString());
if(index >= 0)
{
ui->comboPort->setCurrentIndex(index);
}
ui->comboBaud->setCurrentText(settings.value("baudrate").toString());
ui->comboData->setCurrentIndex(settings.value("databits").toInt());
ui->comboStop->setCurrentIndex(settings.value("stopbits").toInt());
ui->comboParity->setCurrentIndex(settings.value("paritybits").toInt());
QString theme = settings.value("theme").toString();
if(theme == QString("light"))
{
gui_colors[0] = QColor (255, 255, 255, 255); /**< 0: qdark ui dark/background color */
gui_colors[1] = QColor (175, 175, 175, 255); /**< 0: qdark ui dark/background color */
gui_colors[2] = QColor (85, 85, 85, 255); /**< 0: qdark ui dark/background color */
gui_colors[3] = QColor (207, 208, 208, 200); /**< 0: qdark ui dark/background color */
}else if(theme == QString("dark"))
{
gui_colors[0] = QColor (48, 47, 47, 255); /**< 0: qdark ui dark/background color */
gui_colors[1] = QColor (80, 80, 80, 255); /**< 1: qdark ui medium/grid color */
gui_colors[2] = QColor (170, 170, 170, 255); /**< 2: qdark ui light/text color */
gui_colors[3] = QColor (48, 47, 47, 200); /**< 3: qdark ui dark/background color w/transparency */
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Setup the plot area
*/
void MainWindow::setupPlot()
{
/* Remove everything from the plot */
ui->plot->clearItems();
/* Background for the plot area */
ui->plot->setBackground (gui_colors[0]);
/* Used for higher performance (see QCustomPlot real time example) */
ui->plot->setNotAntialiasedElements (QCP::aeAll);
QFont font;
font.setStyleStrategy (QFont::NoAntialias);
ui->plot->legend->setFont (font);
/** See QCustomPlot examples / styled demo **/
/* X Axis: Style */
ui->plot->xAxis->grid()->setPen (QPen(gui_colors[2], 1, Qt::DotLine));
ui->plot->xAxis->grid()->setSubGridPen (QPen(gui_colors[1], 1, Qt::DotLine));
ui->plot->xAxis->grid()->setSubGridVisible (true);
ui->plot->xAxis->setBasePen (QPen (gui_colors[2]));
ui->plot->xAxis->setTickPen (QPen (gui_colors[2]));
ui->plot->xAxis->setSubTickPen (QPen (gui_colors[2]));
ui->plot->xAxis->setUpperEnding (QCPLineEnding::esSpikeArrow);
ui->plot->xAxis->setTickLabelColor (gui_colors[2]);
ui->plot->xAxis->setTickLabelFont (font);
/* Range */
ui->plot->xAxis->setRange (dataPointNumber - ui->spinPoints->value(), dataPointNumber);
/* Y Axis */
ui->plot->yAxis->grid()->setPen (QPen(gui_colors[2], 1, Qt::DotLine));
ui->plot->yAxis->grid()->setSubGridPen (QPen(gui_colors[1], 1, Qt::DotLine));
ui->plot->yAxis->grid()->setSubGridVisible (true);
ui->plot->yAxis->setBasePen (QPen (gui_colors[2]));
ui->plot->yAxis->setTickPen (QPen (gui_colors[2]));
ui->plot->yAxis->setSubTickPen (QPen (gui_colors[2]));
ui->plot->yAxis->setUpperEnding (QCPLineEnding::esSpikeArrow);
ui->plot->yAxis->setTickLabelColor (gui_colors[2]);
ui->plot->yAxis->setTickLabelFont (font);
/* Range */
ui->plot->yAxis->setRange (ui->spinAxesMin->value(), ui->spinAxesMax->value());
/* User can change Y axis tick step with a spin box */
//ui->plot->yAxis->setAutoTickStep (false);
ui->plot->yAxis->ticker()->setTickCount(ui->spinYStep->value());
/* User interactions Drag and Zoom are allowed only on X axis, Y is fixed manually by UI control */
ui->plot->setInteraction (QCP::iRangeDrag, true);
//ui->plot->setInteraction (QCP::iRangeZoom, true);
ui->plot->setInteraction (QCP::iSelectPlottables, true);
ui->plot->setInteraction (QCP::iSelectLegend, true);
ui->plot->axisRect()->setRangeDrag (Qt::Horizontal);
ui->plot->axisRect()->setRangeZoom (Qt::Horizontal);
/* Legend */
QFont legendFont;
legendFont.setPointSize (9);
ui->plot->legend->setVisible (true);
ui->plot->legend->setFont (legendFont);
ui->plot->legend->setBrush (gui_colors[3]);
ui->plot->legend->setBorderPen (gui_colors[2]);
/* By default, the legend is in the inset layout of the main axis rect. So this is how we access it to change legend placement */
ui->plot->axisRect()->insetLayout()->setInsetAlignment (0, Qt::AlignTop|Qt::AlignRight);
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Enable/disable COM controls
* @param enable true enable, false disable
*/
void MainWindow::enable_com_controls (bool enable)
{
/* Com port properties */
ui->comboBaud->setEnabled (enable);
ui->comboData->setEnabled (enable);
ui->comboParity->setEnabled (enable);
ui->comboPort->setEnabled (enable);
ui->comboStop->setEnabled (enable);
/* Toolbar elements */
ui->actionConnect->setEnabled (enable);
ui->actionPause_Plot->setEnabled (!enable);
ui->actionDisconnect->setEnabled (!enable);
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Open the inside serial port; connect its signals
* @param portInfo
* @param baudRate
* @param dataBits
* @param parity
* @param stopBits
*/
void MainWindow::openPort (QSerialPortInfo portInfo, int baudRate, QSerialPort::DataBits dataBits, QSerialPort::Parity parity, QSerialPort::StopBits stopBits)
{
serialPort = new QSerialPort(portInfo, nullptr); // Create a new serial port
connect (this, SIGNAL(portOpenOK()), this, SLOT(portOpenedSuccess())); // Connect port signals to GUI slots
connect (this, SIGNAL(portOpenFail()), this, SLOT(portOpenedFail()));
connect (this, SIGNAL(portClosed()), this, SLOT(onPortClosed()));
connect (this, SIGNAL(newData(QStringList)), this, SLOT(onNewDataArrived(QStringList)));
connect (serialPort, SIGNAL(readyRead()), this, SLOT(readData()));
connect (this, SIGNAL(newData(QStringList)), this, SLOT(saveStream(QStringList)));
if (serialPort->open (QIODevice::ReadWrite))
{
serialPort->setBaudRate (baudRate);
serialPort->setParity (parity);
serialPort->setDataBits (dataBits);
serialPort->setStopBits (stopBits);
emit portOpenOK();
}
else
{
emit portOpenedFail();
qDebug() << serialPort->errorString();
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Slot for closing the port
*/
void MainWindow::onPortClosed()
{
//qDebug() << "Port closed signal received!";
updateTimer.stop();
connected = false;
plotting = false;
//--
closeCsvFile();
disconnect (serialPort, SIGNAL(readyRead()), this, SLOT(readData()));
disconnect (this, SIGNAL(portOpenOK()), this, SLOT(portOpenedSuccess())); // Disconnect port signals to GUI slots
disconnect (this, SIGNAL(portOpenFail()), this, SLOT(portOpenedFail()));
disconnect (this, SIGNAL(portClosed()), this, SLOT(onPortClosed()));
disconnect (this, SIGNAL(newData(QStringList)), this, SLOT(onNewDataArrived(QStringList)));
disconnect (this, SIGNAL(newData(QStringList)), this, SLOT(saveStream(QStringList)));
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Port Combo Box index changed slot; displays info for selected port when combo box is changed
* @param arg1
*/
void MainWindow::on_comboPort_currentIndexChanged (const QString &arg1)
{
QSerialPortInfo selectedPort (arg1); // Dislplay info for selected port
ui->statusBar->showMessage (selectedPort.description());
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Slot for port opened successfully
*/
void MainWindow::portOpenedSuccess()
{
//qDebug() << "Port opened signal received!";
setupPlot(); // Create the QCustomPlot area
ui->statusBar->showMessage ("端口打开成功!");
enable_com_controls (false); // Disable controls if port is open
if(ui->actionRecord_stream->isChecked())
{
//--> Create new CSV file with current date/timestamp
openCsvFile();
}
/* Lock the save option while recording */
ui->actionRecord_stream->setEnabled(false);
updateTimer.start (20); // Slot is refreshed 20 times per second
connected = true; // Set flags
plotting = true;
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Slot for fail to open the port
*/
void MainWindow::portOpenedFail()
{
//qDebug() << "Port cannot be open signal received!";
ui->statusBar->showMessage ("打开失败,请检查该端口是否存在或被占用!");
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Replot
*/
void MainWindow::replot()
{
ui->plot->xAxis->setRange (dataPointNumber - ui->spinPoints->value(), dataPointNumber);
ui->plot->replot();
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Slot for new data from serial port . Data is comming in QStringList and needs to be parsed
* @param newData
*/
void MainWindow::onNewDataArrived(QStringList newData)
{
static int data_members = 0;
static int channel = 0;
static int i = 0;
volatile bool you_shall_NOT_PASS = false;
/* When a fast baud rate is set (921kbps was the first to starts to bug),
this method is called multiple times (2x in the 921k tests), so a flag
is used to throttle
TO-DO: Separate processes, buffer data (1) and process data (2) */
while (you_shall_NOT_PASS) {}
you_shall_NOT_PASS = true;
if (plotting)
{
/* Get size of received list */
data_members = newData.size();
/* Parse data */
for (i = 0; i < data_members; i++)
{
/* Update number of axes if needed */
while (ui->plot->plottableCount() <= channel)
{
/* Add new channel data */
ui->plot->addGraph();
ui->plot->graph()->setPen (line_colors[channels % CUSTOM_LINE_COLORS]);
ui->plot->graph()->setName (QString("Channel %1").arg(channels));
if(ui->plot->legend->item(channels))
{
ui->plot->legend->item (channels)->setTextColor (line_colors[channels % CUSTOM_LINE_COLORS]);
}
ui->listWidget_Channels->addItem(ui->plot->graph()->name());
ui->listWidget_Channels->item(channel)->setForeground(QBrush(line_colors[channels % CUSTOM_LINE_COLORS]));
channels++;
}
/* [TODO] Method selection and plotting */
/* X-Y */
if (0)
{
}
/* Rolling (v1.0.0 compatible) */
else
{
/* Add data to Graph 0 */
ui->plot->graph(channel)->addData (dataPointNumber, newData[channel].toDouble());
/* Increment data number and channel */
channel++;
}
}
/* Post-parsing */
/* X-Y */
if (0)
{
}
/* Rolling (v1.0.0 compatible) */
else
{
dataPointNumber++;
channel = 0;
}
}
you_shall_NOT_PASS = false;
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Slot for spin box for plot minimum value on y axis
* @param arg1
*/
void MainWindow::on_spinAxesMin_valueChanged(int arg1)
{
ui->plot->yAxis->setRangeLower (arg1);
ui->plot->replot();
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Slot for spin box for plot maximum value on y axis
* @param arg1
*/
void MainWindow::on_spinAxesMax_valueChanged(int arg1)
{
ui->plot->yAxis->setRangeUpper (arg1);
ui->plot->replot();
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Read data for inside serial port
*/
void MainWindow::readData()
{
if(serialPort->bytesAvailable()) { // If any bytes are available
QByteArray data = serialPort->readAll(); // Read all data in QByteArray
if(!data.isEmpty()) { // If the byte array is not empty
char *temp = data.data(); // Get a '\0'-terminated char* to the data
if (!filterDisplayedData){
ui->textEdit_UartWindow->append(data);
}
for(int i = 0; temp[i] != '\0'; i++) { // Iterate over the char*
switch(STATE) { // Switch the current state of the message
case WAIT_START: // If waiting for start [$], examine each char
if(temp[i] == START_MSG) { // If the char is $, change STATE to IN_MESSAGE
STATE = IN_MESSAGE;
receivedData.clear(); // Clear temporary QString that holds the message
break; // Break out of the switch
}
break;
case IN_MESSAGE: // If state is IN_MESSAGE
if(temp[i] == END_MSG) { // If char examined is ;, switch state to END_MSG
STATE = WAIT_START;
QStringList incomingData = receivedData.split(' '); // Split string received from port and put it into list
if(filterDisplayedData){
ui->textEdit_UartWindow->append(receivedData);
}
emit newData(incomingData); // Emit signal for data received with the list
break;
}
else if (isdigit (temp[i]) || isspace (temp[i]) || temp[i] =='-' || temp[i] =='.')
{
/* If examined char is a digit, and not '$' or ';', append it to temporary string */
receivedData.append(temp[i]);
}
break;
default: break;
}
}
}
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Number of axes combo; when changed, display axes colors in status bar
* @param index
*/
//void MainWindow::on_comboAxes_currentIndexChanged(int index)
//{
// if(index == 0) {
// ui->statusBar->showMessage("Axis 1: Red");
// } else if(index == 1) {
// ui->statusBar->showMessage("Axis 1: Red; Axis 2: Yellow");
// } else {
// ui->statusBar->showMessage("Axis 1: Red; Axis 2: Yellow; Axis 3: Green");
// }
//}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Spin box for changing the Y Tick step
* @param arg1
*/
void MainWindow::on_spinYStep_valueChanged(int arg1)
{
ui->plot->yAxis->ticker()->setTickCount(arg1);
ui->plot->replot();
ui->spinYStep->setValue(ui->plot->yAxis->ticker()->tickCount());
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Save a PNG image of the plot to current EXE directory
*/
void MainWindow::on_savePNGButton_clicked()
{
ui->plot->savePng (QString::number(dataPointNumber) + ".png", 1920, 1080, 2, 50);
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Prints coordinates of mouse pointer in status bar on mouse release
* @param event
*/
void MainWindow::onMouseMoveInPlot(QMouseEvent *event)
{
int xx = int(ui->plot->xAxis->pixelToCoord(event->x()));
int yy = int(ui->plot->yAxis->pixelToCoord(event->y()));
QString coordinates("X: %1 Y: %2");
coordinates = coordinates.arg(xx).arg(yy);
ui->statusBar->showMessage(coordinates);
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Send plot wheelmouse to spinbox
* @param event
*/
void MainWindow::onMouseWheelInPlot(QWheelEvent *event)
{
QWheelEvent inverted_event = QWheelEvent(event->posF(), event->globalPosF(),
-event->pixelDelta(), -event->angleDelta(),
0, Qt::Vertical, event->buttons(), event->modifiers());
QApplication::sendEvent (ui->spinPoints, &inverted_event);
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Select both line and legend (channel)
* @param plottable
* @param event
*/
void MainWindow::channel_selection (void)
{
/* synchronize selection of graphs with selection of corresponding legend items */
for (int i = 0; i < ui->plot->graphCount(); i++)
{
QCPGraph *graph = ui->plot->graph(i);
QCPPlottableLegendItem *item = ui->plot->legend->itemWithPlottable (graph);
if (item->selected())
{
item->setSelected (true);
// graph->set (true);
}
else
{
item->setSelected (false);
// graph->setSelected (false);
}
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Rename a graph by double clicking on its legend item
* @param legend
* @param item
*/
void MainWindow::legend_double_click(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event)
{
Q_UNUSED (legend)
Q_UNUSED(event)
/* Only react if item was clicked (user could have clicked on border padding of legend where there is no item, then item is 0) */
if (item)
{
QCPPlottableLegendItem *plItem = qobject_cast<QCPPlottableLegendItem*>(item);
bool ok;
#if 0
//QString newName = QInputDialog::getText (this, "设置通道名称", "名称:", QLineEdit::Normal, plItem->plottable()->name(), &ok, Qt::Popup);
#else
QString newName;
QInputDialog dialog;
dialog.setWindowFlags(Qt::FramelessWindowHint); // 隐藏顶部标题栏,无框显示
dialog.setTextEchoMode(QLineEdit::Normal);
dialog.setLabelText("名称:");
dialog.setOkButtonText("确定");
dialog.setCancelButtonText("取消");
if(dialog.exec() == QDialog::Accepted)
{
ok = true;
newName = dialog.textValue();
}else
{
ok = false;
}
#endif
if (ok)
{
plItem->plottable()->setName(newName);
for(int i=0; i<ui->plot->graphCount(); i++)
{
ui->listWidget_Channels->item(i)->setText(ui->plot->graph(i)->name());
}
ui->plot->replot();
}
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Spin box controls how many data points are collected and displayed
* @param arg1
*/
void MainWindow::on_spinPoints_valueChanged (int arg1)
{
Q_UNUSED(arg1)
ui->plot->xAxis->setRange (dataPointNumber - ui->spinPoints->value(), dataPointNumber);
ui->plot->replot();
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Shows a window with instructions
*/
void MainWindow::on_actionHow_to_use_triggered()
{
helpWindow = new HelpWindow (this);
helpWindow->setWindowTitle ("本软件使用方法");
helpWindow->show();
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Connects to COM port or restarts plotting
*/
void MainWindow::on_actionConnect_triggered()
{
if (connected)
{
/* Is connected, restart if paused */
if (!plotting)
{ // Start plotting
updateTimer.start(); // Start updating plot timer
plotting = true;
ui->actionConnect->setEnabled (false);
ui->actionPause_Plot->setEnabled (true);
ui->statusBar->showMessage ("开始绘制!");
}
}
else
{
/* If application is not connected, connect */
/* Get parameters from controls first */
QSerialPortInfo portInfo (ui->comboPort->currentText()); // Temporary object, needed to create QSerialPort
int baudRate = ui->comboBaud->currentText().toInt(); // Get baud rate from combo box
int dataBitsIndex = ui->comboData->currentIndex(); // Get index of data bits combo box
int parityIndex = ui->comboParity->currentIndex(); // Get index of parity combo box
int stopBitsIndex = ui->comboStop->currentIndex(); // Get index of stop bits combo box
QSerialPort::DataBits dataBits;
QSerialPort::Parity parity;
QSerialPort::StopBits stopBits;
/* Set data bits according to the selected index */
switch (dataBitsIndex)
{
case 0:
dataBits = QSerialPort::Data8;
break;
default:
dataBits = QSerialPort::Data7;
}
/* Set parity according to the selected index */
switch (parityIndex)
{
case 0:
parity = QSerialPort::NoParity;
break;
case 1:
parity = QSerialPort::OddParity;
break;
default:
parity = QSerialPort::EvenParity;
}
/* Set stop bits according to the selected index */
switch (stopBitsIndex)
{
case 0:
stopBits = QSerialPort::OneStop;
break;
default:
stopBits = QSerialPort::TwoStop;
}
/* Use local instance of QSerialPort; does not crash */
serialPort = new QSerialPort (portInfo, nullptr);
/* Open serial port and connect its signals */
openPort (portInfo, baudRate, dataBits, parity, stopBits);
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Keep COM port open but pause plotting
*/
void MainWindow::on_actionPause_Plot_triggered()
{
if (plotting)
{
updateTimer.stop(); // Stop updating plot timer
plotting = false;
ui->actionConnect->setEnabled (true);
ui->actionPause_Plot->setEnabled (false);
ui->statusBar->showMessage ("暂停绘制,新数据将被忽略!");
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Keep COM port open but pause plotting
*/
void MainWindow::on_actionRecord_stream_triggered()
{
if (ui->actionRecord_stream->isChecked())
{
ui->statusBar->showMessage ("数据将保存到csv格式文件中!");
}
else
{
ui->statusBar->showMessage ("数据将不在保存到csv格式文件中!");
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Closes COM port and stop plotting
*/
void MainWindow::on_actionDisconnect_triggered()
{
if (connected)
{
serialPort->close(); // Close serial port
emit portClosed(); // Notify application
delete serialPort; // Delete the pointer
serialPort = nullptr; // Assign NULL to dangling pointer
ui->statusBar->showMessage ("关闭端口!");
connected = false; // Set connected status flag to false
ui->actionConnect->setEnabled (true);
plotting = false; // Not plotting anymore
ui->actionPause_Plot->setEnabled (false);
ui->actionDisconnect->setEnabled (false);
ui->actionRecord_stream->setEnabled(true);
receivedData.clear(); // Clear received string
enable_com_controls (true);
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Clear all channels data and reset plot area
*
* This function will not delete the channel itself (legend will stay)
*/
void MainWindow::on_actionClear_triggered()
{
ui->plot->clearPlottables();
ui->listWidget_Channels->clear();
channels = 0;
dataPointNumber = 0;
emit setupPlot();
ui->plot->replot();
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Open a new CSV file to save received data
*
*/
void MainWindow::openCsvFile(void)
{
QString filename = QApplication::applicationDirPath() + "/" + QDateTime::currentDateTime().toString("yyyy-MM-d-HH-mm-ss-")+"data-out.csv";
m_csvFile = new QFile(filename);
if(!m_csvFile)
return;
if (!m_csvFile->open(QIODevice::ReadWrite | QIODevice::Text))
return;
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Open a new CSV file to save received data
*
*/
void MainWindow::closeCsvFile(void)
{
if(!m_csvFile) return;
m_csvFile->close();
if(m_csvFile) delete m_csvFile;
m_csvFile = nullptr;
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @brief Open a new CSV file to save received data
*
*/
void MainWindow::saveStream(QStringList newData)
{
if(!m_csvFile)
return;
if(ui->actionRecord_stream->isChecked())
{
QTextStream out(m_csvFile);
out << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss") << ",";
foreach (const QString &str, newData) {
out << str << ",";
}
out << "\n";
}
}
/** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
void MainWindow::on_pushButton_TextEditHide_clicked()
{
if(ui->pushButton_TextEditHide->isChecked())
{
ui->textEdit_UartWindow->setVisible(false);
ui->pushButton_TextEditHide->setText("显示接收框");
}
else
{
ui->textEdit_UartWindow->setVisible(true);
ui->pushButton_TextEditHide->setText("隐藏接收框");
}
}
void MainWindow::on_pushButton_ShowallData_clicked()
{
if(ui->pushButton_ShowallData->isChecked())
{
filterDisplayedData = false;
ui->pushButton_ShowallData->setText("显示过滤数据");
}
else
{
filterDisplayedData = true;
ui->pushButton_ShowallData->setText("显示原始数据");
}
}
void MainWindow::on_pushButton_AutoScale_clicked()
{
ui->plot->yAxis->rescale(true);
ui->spinAxesMax->setValue(int(ui->plot->yAxis->range().upper) + int(ui->plot->yAxis->range().upper*0.1));
ui->spinAxesMin->setValue(int(ui->plot->yAxis->range().lower) + int(ui->plot->yAxis->range().lower*0.1));
}
void MainWindow::on_pushButton_ResetVisible_clicked()
{
for(int i=0; i<ui->plot->graphCount(); i++)
{
ui->plot->graph(i)->setVisible(true);
ui->listWidget_Channels->item(i)->setBackground(Qt::NoBrush);
}
}
void MainWindow::on_listWidget_Channels_itemDoubleClicked(QListWidgetItem *item)
{
int graphIdx = ui->listWidget_Channels->currentRow();
if(ui->plot->graph(graphIdx)->visible())
{
ui->plot->graph(graphIdx)->setVisible(false);
item->setBackground(Qt::black);
}
else
{
ui->plot->graph(graphIdx)->setVisible(true);
item->setBackground(Qt::NoBrush);
}
ui->plot->replot();
}
void MainWindow::on_pushButton_ClearRecv_clicked()
{
ui->textEdit_UartWindow->clear();
}
void MainWindow::on_actionOpenPath_triggered()
{
// 打开应用程序所在目录
QDesktopServices::openUrl(QUrl::fromLocalFile(QCoreApplication::applicationDirPath() + "/"));
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
if(watched == ui->comboPort)
{
QComboBox* comboBox = qobject_cast<QComboBox *>(watched);
comboBox->clear();
QList<QSerialPortInfo> serials = QSerialPortInfo::availablePorts();
foreach (QSerialPortInfo info, serials)
{
comboBox->addItem(info.portName());
}
}
}
return QMainWindow::eventFilter(watched, event);
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/giteezhangj/QtSerialPortPlotter.git
git@gitee.com:giteezhangj/QtSerialPortPlotter.git
giteezhangj
QtSerialPortPlotter
QtSerialPortPlotter
main

搜索帮助