需求描述
- 接入串口,配置串口顺序进行接收数据;
- 数据分成两个串口分别传入,使用多线程并发接入;
- 时域数据有两个通道(I,Q),分别以实时波形展示;
- 频域数据有三个通道(I,Q,C),C表示联合通道,分别展示FFT波形;
- 状态数据列表实时展示;
- 时域可以配置时间窗口大小,也就是展示的波形最大时间段;
- 频域可以配置频域段;
- 数据支持随时保存,并可以打开查看;
成品展示
实现难点
Qt多线程
Qt实现多线程,有两种方式:
- 一种是使用
QThread
:
1.1 定义个类,继承QThread
;
1.2 然后重写类的run()
方法;
1.3 在主线程中通过类对象的start()
方法启动线程; - 一种是使用自定义类(任务类),继承
QObject
:
2.1 在任务类中定义公共任务方法,实现具体的任务处理逻辑;
2.2 在主线程中创建QThread
对象(千万不要给创建对象指定父对象);
2.3 通过调用QObject
类提供的moveToThread
方法,将任务类对象移动到创建的子线程对象QThread
中;
2.4 调用子线程对象的start()
方法,子线程开始启动,但是移动到子线程中的对象并没有工作;
2.5 通过调用自定义类对象的工作函数,让这个函数开始执行,这时候就是在移动到的子线程中执行的。
两种方式的区别:
- 第一种由于
run()
方法不可以带参数,所以如果要传参数,需要把参数作为成员变量,通过信号槽机制进行传递;第二种没有这种限制,在任务类中定义的任务函数可以带有参数,所以更加灵活; - 第一种方式,一般适用于单个任务,第二种方式,可以有多个任务,而且不同任务可以指定到不同的线程中,也可以指定到相同的线程中,如果指定到同一个线程中,则逻辑顺序为线性执行;
实现细节
任务类:
//tasks.h
#ifndef TASKS_H
#define TASKS_H
#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
class Tasks :public QObject
{
Q_OBJECT
public:
Tasks();
~Tasks();
void working();
void initSerialPort(QString port);
signals:
// void started(int iNum, int qNum);
void started(QString text);
void serialInputError();
private:
QSerialPort *m_serialPort;
};
#endif // TASKS_H
//tasks.cpp
#include "tasks.h"
Tasks::Tasks()
{
}
Tasks::~Tasks()
{
if(m_serialPort!=nullptr)
{
m_serialPort->close();
delete m_serialPort;
m_serialPort = nullptr;
}
}
void Tasks::working()
{
QByteArray buf;
if (m_serialPort){
buf = m_serialPort->readAll();
if (!buf.isEmpty())
{
QString temp = QString(buf);
if(temp.contains("breathch"))
{
emit serialInputError();
m_serialPort->close();
delete m_serialPort;
m_serialPort = nullptr;
return;
}
emit started(temp);
}
}
}
void Tasks::initSerialPort(QString port)
{
QString baudRate = "115200"; //波特率
QString parityBit = "无"; //校验位
QString dataBits = "8"; //数据位
QString stopBits = "1"; //停止位
m_serialPort = new QSerialPort();
m_serialPort->setPortName(port);
if(m_serialPort->open(QIODevice::ReadOnly))
{
if(baudRate == "115200")
{
m_serialPort->setBaudRate(QSerialPort::Baud115200);
}
if(parityBit == "无")
{
m_serialPort->setParity(QSerialPort::NoParity);
}
if(dataBits == "8")
{
m_serialPort->setDataBits(QSerialPort::Data8);
}
if(stopBits == "1")
{
m_serialPort->setStopBits(QSerialPort::OneStop);
}
connect(m_serialPort, &QSerialPort::readyRead, this, &Tasks::working);
}
}
主线程:
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QThread>
#include "qcustomplot/qcustomplot.h"
#include "tasks.h"
#include "labelingdialog.h"
#include <QDateTime>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
struct BreatheDataItem
{
BreatheDataItem()
{
this->breathch = "N/A";
this->breath = 0;
this->movech = "N/A";
this->mean = 0.0;
this->variance = 0.0;
this->range = 0.0;
this->zeronum = 0;
this->status = "N/A";
this->fftMaxValue = 0.0;
}
QString breathch;
int breath;
QString movech;
double mean;
double variance;
double range;
int zeronum;
QString status;
double fftMaxValue;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void initSerialInfo(QString port);
void initUI();
void startSubTread(QString port);
void initPlots();
void cleanPlots();
public slots:
void serialInfoInit(QString port1, QString port2);
void readReadySlot();
void drawPlots(QString text);
void drawFFTPlots(QString text, QCustomPlot *plot);
void mouseMove_slot_I(QMouseEvent *event); // 响应鼠标移动时事件,显示坐标值
void mouseMove_slot_Q(QMouseEvent *event);
void mouseMove_slot_fft_I(QMouseEvent *event);
void mouseMove_slot_fft_Q(QMouseEvent *event);
void mouseMove_slot_fft_C(QMouseEvent *event);
void actionSerialSlot();//串口配置弹窗
void actionResetSlot();//清空配置和数据
void actionTimePlotSlot();//时域波形配置
void actionFrequencyPlotSlot();//频域波形配置
void timeConfigSlot(int value);
void frequencyConfigSlot(int min, int max);
void serialErrorHandler();//串口数据错误的处理
signals:
void killSubThread();
void setTimeSpan(int value);
void setFrequencyXSpan(int min, int max);
void serialInputError();
private:
Ui::MainWindow *ui;
BreatheDataItem m_statusInfo;
QSerialPort *m_serialPort = nullptr;
static int receiveBytes;
static QString preStr;
static int m_s_plot_graph_num;
int m_timeSpan = 30;
int m_frequency_x_min = 0;
int m_frequency_x_max = 300;
QMessageBox *m_warning_box = nullptr;
QString fftIStr;
QString fftQStr;
QString fftCStr;
static QThread *preThread;
static Tasks *preTask;
QCustomPlot * m_plot_i = nullptr;
QCustomPlot * m_plot_q = nullptr;
QCustomPlot * m_fft_plot_i = nullptr;
QCustomPlot * m_fft_plot_q = nullptr;
QCustomPlot * m_fft_plot_c = nullptr;
QVector<QCPItemTracer*> m_tracers;
QVector<QCPItemText*> m_tracerTexts;
QString fftXValuesString = "0,0.585937500000000,1.17187500000000,1.75781250000000,2.34375000000000,2.92968750000000,3.51562500000000,4.10156250000000,4.68750000000000,5.27343750000000,5.85937500000000,6.44531250000000,7.03125000000000,7.61718750000000,8.20312500000000,8.78906250000000,9.37500000000000,9.96093750000000,10.5468750000000,11.1328125000000,11.7187500000000,12.3046875000000,12.8906250000000,13.4765625000000,14.0625000000000,14.6484375000000,15.2343750000000,15.8203125000000,16.4062500000000,16.9921875000000,17.5781250000000,18.1640625000000,18.7500000000000,19.3359375000000,19.9218750000000,20.5078125000000,21.0937500000000,21.6796875000000,22.2656250000000,22.8515625000000,23.4375000000000,24.0234375000000,24.6093750000000,25.1953125000000,25.7812500000000,26.3671875000000,26.9531250000000,27.5390625000000,28.1250000000000,28.7109375000000,29.2968750000000,29.8828125000000,30.4687500000000,31.0546875000000,31.6406250000000,32.2265625000000,32.8125000000000,33.3984375000000,33.9843750000000,34.5703125000000,35.1562500000000,35.7421875000000,36.3281250000000,36.9140625000000,37.5000000000000,38.0859375000000,38.6718750000000,39.2578125000000,39.8437500000000,40.4296875000000,41.0156250000000,41.6015625000000,42.1875000000000,42.7734375000000,43.3593750000000,43.9453125000000,44.5312500000000,45.1171875000000,45.7031250000000,46.2890625000000,46.8750000000000,47.4609375000000,48.0468750000000,48.6328125000000,49.2187500000000,49.8046875000000,50.3906250000000,50.9765625000000,51.5625000000000,52.1484375000000,52.7343750000000,53.3203125000000,53.9062500000000,54.4921875000000,55.0781250000000,55.6640625000000,56.2500000000000,56.8359375000000,57.4218750000000,58.0078125000000,58.5937500000000,59.1796875000000,59.7656250000000,60.3515625000000,60.9375000000000,61.5234375000000,62.1093750000000,62.6953125000000,63.2812500000000,63.8671875000000,64.4531250000000,65.0390625000000,65.6250000000000,66.2109375000000,66.7968750000000,67.3828125000000,67.9687500000000,68.5546875000000,69.1406250000000,69.7265625000000,70.3125000000000,70.8984375000000,71.4843750000000,72.0703125000000,72.6562500000000,73.2421875000000,73.8281250000000,74.4140625000000,75,75.5859375000000,76.1718750000000,76.7578125000000,77.3437500000000,77.9296875000000,78.5156250000000,79.1015625000000,79.6875000000000,80.2734375000000,80.8593750000000,81.4453125000000,82.0312500000000,82.6171875000000,83.2031250000000,83.7890625000000,84.3750000000000,84.9609375000000,85.5468750000000,86.1328125000000,86.7187500000000,87.3046875000000,87.8906250000000,88.4765625000000,89.0625000000000,89.6484375000000,90.2343750000000,90.8203125000000,91.4062500000000,91.9921875000000,92.5781250000000,93.1640625000000,93.7500000000000,94.3359375000000,94.9218750000000,95.5078125000000,96.0937500000000,96.6796875000000,97.2656250000000,97.8515625000000,98.4375000000000,99.0234375000000,99.6093750000000,100.195312500000,100.781250000000,101.367187500000,101.953125000000,102.539062500000,103.125000000000,103.710937500000,104.296875000000,104.882812500000,105.468750000000,106.054687500000,106.640625000000,107.226562500000,107.812500000000,108.398437500000,108.984375000000,109.570312500000,110.156250000000,110.742187500000,111.328125000000,111.914062500000,112.500000000000,113.085937500000,113.671875000000,114.257812500000,114.843750000000,115.429687500000,116.015625000000,116.601562500000,117.187500000000,117.773437500000,118.359375000000,118.945312500000,119.531250000000,120.117187500000,120.703125000000,121.289062500000,121.875000000000,122.460937500000,123.046875000000,123.632812500000,124.218750000000,124.804687500000,125.390625000000,125.976562500000,126.562500000000,127.148437500000,127.734375000000,128.320312500000,128.906250000000,129.492187500000,130.078125000000,130.664062500000,131.250000000000,131.835937500000,132.421875000000,133.007812500000,133.593750000000,134.179687500000,134.765625000000,135.351562500000,135.937500000000,136.523437500000,137.109375000000,137.695312500000,138.281250000000,138.867187500000,139.453125000000,140.039062500000,140.625000000000,141.210937500000,141.796875000000,142.382812500000,142.968750000000,143.554687500000,144.140625000000,144.726562500000,145.312500000000,145.898437500000,146.484375000000,147.070312500000,147.656250000000,148.242187500000,148.828125000000,149.414062500000,150,150.585937500000,151.171875000000,151.757812500000,152.343750000000,152.929687500000,153.515625000000,154.101562500000,154.687500000000,155.273437500000,155.859375000000,156.445312500000,157.031250000000,157.617187500000,158.203125000000,158.789062500000,159.375000000000,159.960937500000,160.546875000000,161.132812500000,161.718750000000,162.304687500000,162.890625000000,163.476562500000,164.062500000000,164.648437500000,165.234375000000,165.820312500000,166.406250000000,166.992187500000,167.578125000000,168.164062500000,168.750000000000,169.335937500000,169.921875000000,170.507812500000,171.093750000000,171.679687500000,172.265625000000,172.851562500000,173.437500000000,174.023437500000,174.609375000000,175.195312500000,175.781250000000,176.367187500000,176.953125000000,177.539062500000,178.125000000000,178.710937500000,179.296875000000,179.882812500000,180.468750000000,181.054687500000,181.640625000000,182.226562500000,182.812500000000,183.398437500000,183.984375000000,184.570312500000,185.156250000000,185.742187500000,186.328125000000,186.914062500000,187.500000000000,188.085937500000,188.671875000000,189.257812500000,189.843750000000,190.429687500000,191.015625000000,191.601562500000,192.187500000000,192.773437500000,193.359375000000,193.945312500000,194.531250000000,195.117187500000,195.703125000000,196.289062500000,196.875000000000,197.460937500000,198.046875000000,198.632812500000,199.218750000000,199.804687500000,200.390625000000,200.976562500000,201.562500000000,202.148437500000,202.734375000000,203.320312500000,203.906250000000,204.492187500000,205.078125000000,205.664062500000,206.250000000000,206.835937500000,207.421875000000,208.007812500000,208.593750000000,209.179687500000,209.765625000000,210.351562500000,210.937500000000,211.523437500000,212.109375000000,212.695312500000,213.281250000000,213.867187500000,214.453125000000,215.039062500000,215.625000000000,216.210937500000,216.796875000000,217.382812500000,217.968750000000,218.554687500000,219.140625000000,219.726562500000,220.312500000000,220.898437500000,221.484375000000,222.070312500000,222.656250000000,223.242187500000,223.828125000000,224.414062500000,225,225.585937500000,226.171875000000,226.757812500000,227.343750000000,227.929687500000,228.515625000000,229.101562500000,229.687500000000,230.273437500000,230.859375000000,231.445312500000,232.031250000000,232.617187500000,233.203125000000,233.789062500000,234.375000000000,234.960937500000,235.546875000000,236.132812500000,236.718750000000,237.304687500000,237.890625000000,238.476562500000,239.062500000000,239.648437500000,240.234375000000,240.820312500000,241.406250000000,241.992187500000,242.578125000000,243.164062500000,243.750000000000,244.335937500000,244.921875000000,245.507812500000,246.093750000000,246.679687500000,247.265625000000,247.851562500000,248.437500000000,249.023437500000,249.609375000000,250.195312500000,250.781250000000,251.367187500000,251.953125000000,252.539062500000,253.125000000000,253.710937500000,254.296875000000,254.882812500000,255.468750000000,256.054687500000,256.640625000000,257.226562500000,257.812500000000,258.398437500000,258.984375000000,259.570312500000,260.156250000000,260.742187500000,261.328125000000,261.914062500000,262.500000000000,263.085937500000,263.671875000000,264.257812500000,264.843750000000,265.429687500000,266.015625000000,266.601562500000,267.187500000000,267.773437500000,268.359375000000,268.945312500000,269.531250000000,270.117187500000,270.703125000000,271.289062500000,271.875000000000,272.460937500000,273.046875000000,273.632812500000,274.218750000000,274.804687500000,275.390625000000,275.976562500000,276.562500000000,277.148437500000,277.734375000000,278.320312500000,278.906250000000,279.492187500000,280.078125000000,280.664062500000,281.250000000000,281.835937500000,282.421875000000,283.007812500000,283.593750000000,284.179687500000,284.765625000000,285.351562500000,285.937500000000,286.523437500000,287.109375000000,287.695312500000,288.281250000000,288.867187500000,289.453125000000,290.039062500000,290.625000000000,291.210937500000,291.796875000000,292.382812500000,292.968750000000,293.554687500000,294.140625000000,294.726562500000,295.312500000000,295.898437500000,296.484375000000,297.070312500000,297.656250000000,298.242187500000,298.828125000000,299.414062500000,300";
QVector<double> m_fft_x;
QVector<double> m_fft_y;
int writeToFile(QString path, QString text, int recordType);//recordType=0:IQ通道时域数据,recordType=1:状态信息数据
void initTracers();
bool isSerialExist();
void updateUiByKey(QString key, QString value);
void updateUiByQString(QString qstring);
void cleanFFTPlots();
void recordHardWareVersion(QString version);
QString recordStr;
QString statusInfoStr;
bool isRecord = false;
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "serialconfigdialog.h"
#include "timeplotconfigdialog.h"
#include "frequencyplotconfigdialog.h"
#include "scenedialog.h"
int MainWindow::receiveBytes = 0;
QThread * MainWindow::preThread = nullptr;
Tasks * MainWindow::preTask = nullptr;
QString MainWindow::preStr;
int MainWindow::m_s_plot_graph_num = 5;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
initUI();
initPlots();
}
MainWindow::~MainWindow()
{
delete ui;
if(m_serialPort)
{
m_serialPort->close();
delete m_serialPort;
m_serialPort = nullptr;
}
}
void MainWindow::initUI()
{
setFont(QFont("Microsoft Yahei", 9));
setWindowIcon(QIcon(":/images/breathe.png"));
setWindowTitle("呼吸监测v1.8.0 CopyRight©2013 PowerBy 工程化部");
ui->actionserial->setIcon(QIcon(":/images/serial_port.png"));
ui->actionreset->setIcon(QIcon(":/images/clear.png"));
// ui->centralwidget->setStyleSheet("background:#fff");
ui->label_breathch->setText(m_statusInfo.breathch);
ui->label_breathch->setStyleSheet("color:blue");
ui->label_breathTimes->setText(QString::number(m_statusInfo.breath));
ui->label_breathTimes->setStyleSheet("color:blue");
ui->label_movech->setText(m_statusInfo.movech);
ui->label_movech->setStyleSheet("color:blue");
ui->label_mean->setText(QString::number(m_statusInfo.mean));
ui->label_mean->setStyleSheet("color:blue");
ui->label_variance->setText(QString::number(m_statusInfo.variance));
ui->label_variance->setStyleSheet("color:blue");
ui->label_range->setText(QString::number(m_statusInfo.range));
ui->label_range->setStyleSheet("color:blue");
ui->label_zeronum->setText(QString::number(m_statusInfo.zeronum));
ui->label_zeronum->setStyleSheet("color:blue");
ui->label_status->setText(m_statusInfo.status);
ui->label_status->setStyleSheet("color:blue");
ui->label_fft_max->setText(QString::number(m_statusInfo.fftMaxValue));
ui->label_fft_max->setStyleSheet("color:blue");
ui->btn_record_start->setAutoDefault(true);
defaultPath = QDir::cleanPath(QDir::currentPath() + QDir::separator() + QString("data"));
connect(ui->btn_set_directory, &QPushButton::clicked, this, &MainWindow::onSetDirectory);
connect(ui->btn_labeling, &QPushButton::clicked, this, &MainWindow::onStartLabeling);
connect(ui->btn_record_start, &QPushButton::clicked, this, &MainWindow::onRecordStart);
connect(ui->btn_record_stop, &QPushButton::clicked, this, &MainWindow::onRecordStop);
connect(ui->btn_record_dir, &QPushButton::clicked, this, &MainWindow::onOpenRecordDir);
connect(ui->btn_set_scene, &QPushButton::clicked, this, &MainWindow::onSetScene);
connect(ui->actionserial, &QAction::triggered, this, &MainWindow::actionSerialSlot);
connect(ui->actionreset, &QAction::triggered, this, &MainWindow::actionResetSlot);
connect(ui->actiontimeplot, &QAction::triggered, this, &MainWindow::actionTimePlotSlot);
connect(ui->actionfrequencyplot, &QAction::triggered, this, &MainWindow::actionFrequencyPlotSlot);
connect(this, &MainWindow::serialInputError, this, &MainWindow::serialErrorHandler);
connect(this, &MainWindow::startWriteLabelFile, this, &MainWindow::onStartWriteLabelFile);
}
bool MainWindow::isSerialExist()
{
const auto infos = QSerialPortInfo::availablePorts();
QStringList portNames;
for(const QSerialPortInfo &info : infos)
{
QSerialPort serial;
serial.setPort(info);
if(serial.open(QIODevice::ReadOnly))
{
portNames.append(info.portName());
serial.close();
}
}
if(portNames.size() == 0)
{
QMessageBox box(QMessageBox::Critical, "提示", "没有检测到串口连接,请检测是否连接?", QMessageBox::Ok);
box.setButtonText(QMessageBox::Ok, "确定");
box.exec();
return false;
}
else
{
return true;
}
}
void MainWindow::actionSerialSlot()
{
if(isSerialExist())
{
SerialConfigDialog *dlg = new SerialConfigDialog(this);
connect(dlg, &SerialConfigDialog::infoConfigEnd, this, &MainWindow::serialInfoInit);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
}
}
void MainWindow::actionTimePlotSlot()
{
TimePlotConfigDialog *dlg = new TimePlotConfigDialog;
connect(dlg, &TimePlotConfigDialog::timeConfigEnd, this, &MainWindow::timeConfigSlot);
connect(this, &MainWindow::setTimeSpan, dlg, &TimePlotConfigDialog::setTimeSpanSlot);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
emit setTimeSpan(m_timeSpan);
}
void MainWindow::actionFrequencyPlotSlot()
{
FrequencyPlotConfigDialog *dlg = new FrequencyPlotConfigDialog;
connect(dlg, &FrequencyPlotConfigDialog::frequencyConfigEnd, this, &MainWindow::frequencyConfigSlot);
connect(this, &MainWindow::setFrequencyXSpan, dlg, &FrequencyPlotConfigDialog::setFrequencyXSpanSlot);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
emit setFrequencyXSpan(m_frequency_x_min, m_frequency_x_max);
}
void MainWindow::timeConfigSlot(int value)
{
m_timeSpan = value;
cleanPlots();
}
void MainWindow::frequencyConfigSlot(int min, int max)
{
m_frequency_x_min = min;
m_frequency_x_max = max;
cleanFFTPlots();
}
void MainWindow::serialInfoInit(QString port1, QString port2)
{
initSerialInfo(port1);
startSubTread(port2);
}
void MainWindow::actionResetSlot()
{
QMessageBox box;
box.setIcon(QMessageBox::Warning);
box.setText("清空配置");
box.setInformativeText("会清空所有配置和数据,是否确认要执行?");
box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
box.setDefaultButton(QMessageBox::Ok);
box.setButtonText(QMessageBox::Ok, QString("确 定"));
box.setButtonText(QMessageBox::Cancel, QString("取 消"));
int ret = box.exec();
if(ret == QMessageBox::Cancel)
{
return;
}
if(m_serialPort)
{
m_serialPort->close();
delete m_serialPort;
m_serialPort = nullptr;
}
emit killSubThread();
cleanPlots();
}
void MainWindow::initPlots()
{
m_plot_i = ui->plot_I;
m_plot_q = ui->plot_Q;
m_fft_plot_i = ui->fft_plot_i;
m_fft_plot_q = ui->fft_plot_q;
m_fft_plot_c = ui->fft_plot_c;
m_plot_i->xAxis->setLabel("Time");
m_plot_i->yAxis->setLabel("I");
m_plot_q->xAxis->setLabel("Time");
m_plot_q->yAxis->setLabel("Q");
m_fft_plot_i->xAxis->setLabel("Hz");
m_fft_plot_i->yAxis->setLabel("I");
m_fft_plot_q->xAxis->setLabel("Hz");
m_fft_plot_q->yAxis->setLabel("Q");
m_fft_plot_c->xAxis->setLabel("Hz");
m_fft_plot_c->yAxis->setLabel("C");
m_plot_i->addGraph(); // blue line
m_plot_i->graph(0)->setPen(QPen(QColor(40, 110, 255)));
m_plot_q->addGraph(); // red line
m_plot_q->graph(0)->setPen(QPen(QColor(255, 110, 40)));
m_fft_plot_i->addGraph();
m_fft_plot_i->graph(0)->setPen(QPen(QColor(50,205,50)));//绿色
m_fft_plot_q->addGraph();
m_fft_plot_q->graph(0)->setPen(QPen(QColor(153,50,204)));//紫色
m_fft_plot_c->addGraph();
m_fft_plot_c->graph(0)->setPen(QPen(QColor(230,162,60)));//橙色
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
timeTicker->setTimeFormat("%h:%m:%s");
m_plot_i->xAxis->setTicker(timeTicker);
m_plot_i->axisRect()->setupFullAxesBox();
m_plot_i->yAxis->setRange(0, 2100);
m_plot_q->xAxis->setTicker(timeTicker);
m_plot_q->axisRect()->setupFullAxesBox();
m_plot_q->yAxis->setRange(0, 2100);
m_fft_plot_i->axisRect()->setupFullAxesBox();
m_fft_plot_q->axisRect()->setupFullAxesBox();
m_fft_plot_c->axisRect()->setupFullAxesBox();
// m_plot_i->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
// m_plot_q->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
// make left and bottom axes transfer their ranges to right and top axes:
connect(m_plot_i->xAxis, SIGNAL(rangeChanged(QCPRange)), m_plot_i->xAxis2, SLOT(setRange(QCPRange)));
connect(m_plot_i->yAxis, SIGNAL(rangeChanged(QCPRange)), m_plot_i->yAxis2, SLOT(setRange(QCPRange)));
connect(m_plot_q->xAxis, SIGNAL(rangeChanged(QCPRange)), m_plot_q->xAxis2, SLOT(setRange(QCPRange)));
connect(m_plot_q->yAxis, SIGNAL(rangeChanged(QCPRange)), m_plot_q->yAxis2, SLOT(setRange(QCPRange)));
connect(m_fft_plot_i->xAxis, SIGNAL(rangeChanged(QCPRange)), m_fft_plot_i->xAxis2, SLOT(setRange(QCPRange)));
connect(m_fft_plot_i->yAxis, SIGNAL(rangeChanged(QCPRange)), m_fft_plot_i->yAxis2, SLOT(setRange(QCPRange)));
connect(m_fft_plot_q->xAxis, SIGNAL(rangeChanged(QCPRange)), m_fft_plot_q->xAxis2, SLOT(setRange(QCPRange)));
connect(m_fft_plot_q->yAxis, SIGNAL(rangeChanged(QCPRange)), m_fft_plot_q->yAxis2, SLOT(setRange(QCPRange)));
connect(m_fft_plot_c->xAxis, SIGNAL(rangeChanged(QCPRange)), m_fft_plot_c->xAxis2, SLOT(setRange(QCPRange)));
connect(m_fft_plot_c->yAxis, SIGNAL(rangeChanged(QCPRange)), m_fft_plot_c->yAxis2, SLOT(setRange(QCPRange)));
//初始化fft横坐标
QStringList xList = fftXValuesString.split(',');
for(QStringList::const_iterator it = xList.cbegin(); it != xList.cend(); ++it)
{
m_fft_x.push_back((*it).toDouble());
}
initTracers();
}
void MainWindow::initTracers()
{
m_tracers.resize(m_s_plot_graph_num);
m_tracerTexts.resize(m_s_plot_graph_num);
//生成游标
for(int i = 0; i < m_s_plot_graph_num; i++)
{
QCustomPlot *plot = nullptr;
if(i==0)
{
plot = m_plot_i;
}
else if(i==1)
{
plot = m_plot_q;
}
else if(i==2)
{
plot = m_fft_plot_i;
}
else if(i==3)
{
plot = m_fft_plot_q;
}
else if(i==4)
{
plot = m_fft_plot_c;
}
m_tracers[i] = new QCPItemTracer(plot); //生成游标
m_tracers[i]->setPen(QPen(Qt::black));//圆圈轮廓颜色
m_tracers[i]->setBrush(QBrush(Qt::red));//圆圈圈内颜色
m_tracers[i]->setStyle(QCPItemTracer::tsCircle);//圆圈
m_tracers[i]->setSize(5);//设置大小
//生成游标说明
m_tracerTexts[i] = new QCPItemText(plot); //生成游标说明
m_tracerTexts[i]->setLayer("overlay");//设置图层为overlay,因为需要频繁刷新
m_tracerTexts[i]->setPen(QPen(Qt::black));//设置游标说明颜色
m_tracerTexts[i]->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop);//左上
m_tracerTexts[i]->position->setParentAnchor(m_tracers[i]->position);//将游标说明锚固在tracer位置处,实现自动跟随
m_tracerTexts[i]->setVisible(false);
if(i==0)
{
connect(plot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove_slot_I(QMouseEvent*)));
}
else if(i==1)
{
connect(plot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove_slot_Q(QMouseEvent*)));
}
else if(i==2)
{
connect(plot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove_slot_fft_I(QMouseEvent*)));
}
else if(i==3)
{
connect(plot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove_slot_fft_Q(QMouseEvent*)));
}
else if(i==4)
{
connect(plot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove_slot_fft_C(QMouseEvent*)));
}
}
}
void MainWindow::cleanPlots()
{
m_plot_i->graph(0)->data()->clear();
m_plot_q->graph(0)->data()->clear();
m_fft_plot_i->graph(0)->data()->clear();
m_fft_plot_q->graph(0)->data()->clear();
m_fft_plot_c->graph(0)->data()->clear();
for(int i = 0; i < m_s_plot_graph_num; i++)
{
if(m_tracers[i])
{
m_tracers[i]->setVisible(false);
}
if(m_tracerTexts[i])
{
m_tracerTexts[i]->setVisible(false);
}
}
m_plot_i->replot();
m_plot_q->replot();
m_fft_plot_i->replot();
m_fft_plot_q->replot();
m_fft_plot_c->replot();
ui->label_breathch->setText("N/A");
ui->label_breathTimes->setText("0");
ui->label_movech->setText("N/A");
ui->label_mean->setText("0");
ui->label_variance->setText("0");
ui->label_range->setText("0");
ui->label_zeronum->setText("0");
ui->label_status->setText("N/A");
}
void MainWindow::initSerialInfo(QString port)
{
QString baudRate = "115200"; //波特率
QString parityBit = "无"; //校验位
QString dataBits = "8"; //数据位
QString stopBits = "1"; //停止位
m_serialPort = new QSerialPort();
m_serialPort->setPortName(port);
if(m_serialPort->open(QIODevice::ReadOnly))
{
if(baudRate == "115200")
{
m_serialPort->setBaudRate(QSerialPort::Baud115200);
}
if(parityBit == "无")
{
m_serialPort->setParity(QSerialPort::NoParity);
}
if(dataBits == "8")
{
m_serialPort->setDataBits(QSerialPort::Data8);
}
if(stopBits == "1")
{
m_serialPort->setStopBits(QSerialPort::OneStop);
}
connect(m_serialPort, &QSerialPort::readyRead, this, &MainWindow::readReadySlot);
}
}
void MainWindow::readReadySlot()
{
QByteArray buf;
if (m_serialPort){
buf = m_serialPort->readAll();
if (!buf.isEmpty())
{
QString myStrTemp = QString(buf);
// qDebug()<<myStrTemp;
// if(!myStrTemp.contains("###1")&&!myStrTemp.contains("###2")&&!myStrTemp.contains("###3"))
// {
// if(m_serialPort)
// {
// m_serialPort->close();
// delete m_serialPort;
// m_serialPort = nullptr;
// }
// emit serialInputError();
// return;
// }
if(!myStrTemp.contains("\r\n"))
{
preStr.append(myStrTemp);
}
else
{
int idx = myStrTemp.indexOf("\r\n");
preStr.append(myStrTemp.constData(),idx);
//qDebug()<<preStr;
if(preStr.startsWith("###1,"))
{
//qDebug()<<preStr;
drawFFTPlots(preStr, m_fft_plot_i);
}
else if(preStr.startsWith("###2,"))
{
//qDebug()<<preStr;
drawFFTPlots(preStr, m_fft_plot_q);
}
else if(preStr.startsWith("###3,"))
{
//qDebug()<<preStr;
drawFFTPlots(preStr, m_fft_plot_c);
}
else if(preStr.startsWith("====================================================="))//breachch
{
preStr.replace("=====================================================","");
if(preStr.contains("\r\n"))
{
int idx = preStr.indexOf("\r\n");
QString substr = preStr.mid(0,idx);
QString substr2 = preStr.mid(idx+2, preStr.size()-idx-2);
//qDebug()<<"123:"<<substr2;
if(substr2.startsWith(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")))
{
if(substr2.contains("\r\n"))
{
int idx = substr2.indexOf("\r\n");
//QString subsubstr = substr2.mid(0,idx);
QString subsubstr2 = substr2.mid(idx+2, preStr.size()-idx-2);
if(subsubstr2.startsWith("@@@@@@@@@@@@@@@@@@@@@@@@@@@@"))
{
subsubstr2.replace("@@@@@@@@@@@@@@@@@@@@@@@@@@@@","");
updateUiByQString(subsubstr2);
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+subsubstr2+"\r\n");
}
else
{
statusInfoStr.clear();
}
return;
}
}
else
{
updateUiByQString(substr);
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+substr+"\r\n");
}
else
{
statusInfoStr.clear();
}
}
preStr = substr;
}
return;
}
//qDebug()<<preStr;
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+preStr+"\r\n");
}
else
{
statusInfoStr.clear();
}
updateUiByQString(preStr);
}
else if(preStr.startsWith("@@@@@@@@@@@@@@@@@@@@@@@@@@@@"))//move
{
preStr.replace("@@@@@@@@@@@@@@@@@@@@@@@@@@@@","");
if(preStr.contains("\r\n"))
{
int idx = preStr.indexOf("\r\n");
QString substr = preStr.mid(0,idx);
QString substr2 = preStr.mid(idx+2, preStr.size()-idx-2);
if(substr2.startsWith("###1,"))
{
drawFFTPlots(substr2, m_fft_plot_i);
}
preStr = substr;
}
//qDebug()<<preStr;
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+preStr+"\r\n");
}
else
{
statusInfoStr.clear();
}
updateUiByQString(preStr);
}
else if(preStr.startsWith("--------------------------------------"))//move body move
{
preStr.replace("--------------------------------------","");
//qDebug()<<preStr;
if(preStr.contains("\r\n"))
{
int idx = preStr.indexOf("\r\n");
QString substr = preStr.mid(0,idx);
QString substr2 = preStr.mid(idx+2, preStr.size()-idx-2);
updateUiByQString(substr);
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+substr+"\r\n");
}
else
{
statusInfoStr.clear();
}
updateUiByQString(substr2);
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+substr2+"\r\n");
}
else
{
statusInfoStr.clear();
}
}
else
{
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+preStr+"\r\n");
}
else
{
statusInfoStr.clear();
}
updateUiByQString(preStr);
}
}
else if(preStr.startsWith("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"))//handware version
{
preStr.replace("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!","");
if(preStr.contains("\r\n"))
{
int idx = preStr.indexOf("\r\n");
QString substr = preStr.mid(0,idx);
QString substr2 = preStr.mid(idx+2, preStr.size()-idx-2);
if(substr2.startsWith("@@@@@@@@@@@@@@@@@@@@@@@@@@@@"))
{
substr2.replace("@@@@@@@@@@@@@@@@@@@@@@@@@@@@","");
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
statusInfoStr.append(dataTimeStr+"\t"+substr2+"\r\n");
}
else
{
statusInfoStr.clear();
}
updateUiByQString(substr2);
}
preStr = substr;
}
if(!preStr.isEmpty())
{
recordHardWareVersion(preStr);
}
}
preStr.clear();
if(idx != myStrTemp.size()-2)
{
preStr.append(myStrTemp.midRef(idx+2,myStrTemp.size()-2-idx));
}
/* if(preStr.contains("\r\n"))
{
int idx = preStr.indexOf("\r\n");
QString substr = preStr.mid(idx+2, preStr.size()-idx-2);
if(substr.contains("movech"))
{
//直接刷新move属性的值
if(substr.contains("\r\n"))
{
int idx = substr.indexOf("\r\n");
substr = substr.mid(0,idx);
//updateUiByQString(substr);
preStr.clear();
preStr.append(substr.midRef(idx+2, substr.size()-idx-2));
}
qDebug()<<substr;
updateUiByQString(substr);
}
else
{
QString breathStr = preStr.mid(0, idx);
//直接刷新breath属性值,breath是1秒1次,move是3秒1次
qDebug()<<breathStr;
updateUiByQString(breathStr);
preStr.clear();
preStr.append(substr);
}
}
if(preStr.startsWith("###1,"))
{
//qDebug()<<preStr;
drawFFTPlots(preStr, m_fft_plot_i);
}
else if(preStr.startsWith("###2,"))
{
//qDebug()<<preStr;
drawFFTPlots(preStr, m_fft_plot_q);
}
else if(preStr.startsWith("###3,"))
{
//qDebug()<<preStr;
drawFFTPlots(preStr, m_fft_plot_c);
}
else if(preStr.startsWith("breathch"))
{
if(preStr.contains("\r\n"))
{
int idx = preStr.indexOf("\r\n");
QString breathStr = preStr.mid(0, idx);
qDebug()<<breathStr;
updateUiByQString(breathStr);
}
}
// else if(preStr.startsWith("movech"))//前面已经显示过了,不需要了
// {
// qDebug()<<preStr;
// }
preStr.clear();
if(idx != myStrTemp.size()-2)
{
preStr.append(myStrTemp.midRef(idx+2,myStrTemp.size()-2-idx));
}*/
}
}
buf.clear();
}
}
void MainWindow::updateUiByQString(QString qstring)
{
QStringList sList = qstring.split(',');
for(QStringList::const_iterator it=sList.cbegin(); it != sList.cend(); ++it)
{
QStringList itemList = (*it).split(':');
if(itemList.size()==2)
{
QString key = itemList[0];
updateUiByKey(key, itemList[1]);
}
}
}
void MainWindow::cleanFFTPlots()
{
m_fft_plot_i->graph(0)->data()->clear();
m_fft_plot_q->graph(0)->data()->clear();
m_fft_plot_c->graph(0)->data()->clear();
for(int i = 0; i < 3; i++)
{
if(m_tracers[i+2])
{
m_tracers[i+2]->setVisible(false);
}
if(m_tracerTexts[i+2])
{
m_tracerTexts[i+2]->setVisible(false);
}
}
m_fft_plot_i->replot();
m_fft_plot_q->replot();
m_fft_plot_c->replot();
}
bool isVersionSave = false;
void MainWindow::recordHardWareVersion(QString version)
{
if(isVersionSave==false)
{
QFile file(defaultPath+"/version.txt");
isVersionSave = true;
bool isOk = file.open(QIODevice::WriteOnly);
if(isOk)
{
file.write(version.toUtf8());
}
file.close();
}
}
void MainWindow::updateUiByKey(QString key, QString value)
{
if(key == "movech")
{
ui->label_movech->setText(value);
}
if(key == "mean")
{
ui->label_mean->setText(value);
}
if(key == "variance")
{
ui->label_variance->setText(value);
}
if(key == "range")
{
ui->label_range->setText(value);
}
if(key == "zeronum")
{
ui->label_zeronum->setText(value);
}
if(key == "status")
{
ui->label_status->setText(value);
}
if(key == "breathch")
{
ui->label_breathch->setText(value);
}
if(key == "breath")
{
ui->label_breathTimes->setText(value);
}
if(key == "max_value")
{
ui->label_fft_max->setText(value);
}
}
void MainWindow::startSubTread(QString port)
{
QThread *t1 = new QThread;
preThread = t1;
Tasks *task = new Tasks;
task->initSerialPort(port);
connect(task, &Tasks::started, this, &MainWindow::drawPlots);
connect(task, &Tasks::serialInputError, this, &MainWindow::serialErrorHandler);
task->moveToThread(t1);
t1->start();
disconnect(this, &MainWindow::killSubThread, this, nullptr);
connect(this, &MainWindow::killSubThread, this, [=]()mutable{
if(t1 != nullptr)
{
t1->terminate();
delete t1;
t1 = nullptr;
preThread = nullptr;
delete task;
task = nullptr;
preTask = nullptr;
}
});
disconnect(this, &MainWindow::destroyed, this, nullptr);
connect(this, &MainWindow::destroyed, this, [=]()mutable{//窗口关闭释放线程
if(t1 != nullptr && t1 == preThread)
{
t1->quit();
t1->wait();
t1->deleteLater();
delete t1;
t1 = nullptr;
}
if(task != nullptr && task == preTask)
{
delete task;
task = nullptr;
}
});
}
void MainWindow::serialErrorHandler()
{
if(m_warning_box == nullptr)
{
m_warning_box = new QMessageBox;
m_warning_box->setIcon(QMessageBox::Warning);
m_warning_box->setText("配置错误");
m_warning_box->setInformativeText("串口数据不一致,检查串口配置是否有误?");
m_warning_box->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
m_warning_box->setDefaultButton(QMessageBox::Ok);
m_warning_box->setButtonText(QMessageBox::Ok, QString("确 定"));
m_warning_box->setButtonText(QMessageBox::Cancel, QString("取 消"));
m_warning_box->open();
}
else
{
m_warning_box->reject();
m_warning_box->open();
}
if(m_warning_box->result() == QMessageBox::Cancel)
{
return;
}
if(m_serialPort)
{
m_serialPort->close();
delete m_serialPort;
m_serialPort = nullptr;
}
emit killSubThread();
cleanPlots();
}
void MainWindow::onSetDirectory()
{
auto selectDir = QFileDialog::getExistingDirectory();
defaultPath = selectDir;
}
void MainWindow::onStartLabeling()
{
LabelingDialog *dlg = new LabelingDialog;
emit startWriteLabelFile(QDateTime::currentDateTime());
connect(dlg, &LabelingDialog::writeToLabelFile, this, &::MainWindow::onWriteToLabelFile);
connect(dlg, &LabelingDialog::writeFileDone, this, &MainWindow::onWriteLabelFileDone);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
}
static int elaspedTime = 0;
void MainWindow::drawPlots(QString text)
{
QStringList list = text.split("\r\n");
int count = list.size();
if(count>2)//表示是第一次获得数据
{
QString temp = list[0];//第一个数据可能会包含特殊字符???\n,进行如下过滤
QStringList pair = temp.split(',');
QString tl = pair[0];
tl.replace(QRegExp("(\\D+)\n(\\d+)$"), "\\2");
QString tr= pair[1];
list[0] = QString("%1,%2").arg(tl, tr);
}
if(!list.isEmpty())
{
list.pop_back();//去掉空字符串
}
int len = list.size();
if(len >= 1)
{
for(int i = 0; i < len; i++)
{
elaspedTime +=50;
double x = (double)elaspedTime/1000;
if(isRecord)
{
QString dataTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz");
recordStr.append(dataTimeStr+"\t"+list[i]+"\r\n");
}
else
{
recordStr.clear();
}
QStringList slist = list[i].split(',');
double y1 = slist[0].toDouble();
double y2 = slist[1].toDouble();
m_plot_i->graph(0)->addData(x, y1);
m_plot_q->graph(0)->addData(x, y2);
m_plot_i->graph(0)->rescaleAxes();
m_plot_q->graph(0)->rescaleAxes();
m_plot_i->xAxis->setRange(x, m_timeSpan, Qt::AlignRight);//setRange一定要在rescaleAxes之后,否则不生效
m_plot_q->xAxis->setRange(x, m_timeSpan, Qt::AlignRight);
m_plot_i->replot();
m_plot_q->replot();
}
}
}
void MainWindow::drawFFTPlots(QString text, QCustomPlot *plot)
{
QStringList list = text.split(',');
list.pop_front();//删除"###1"
if(!m_fft_y.isEmpty())
{
m_fft_y.clear();
}
for(QStringList::const_iterator it = list.cbegin(); it != list.cend(); ++it)
{
m_fft_y.push_back((*it).toDouble());
}
if(m_fft_y.size()>513)
{
m_fft_y.resize(513);
}
int min_indx = 0;
int max_indx = 512;
bool is_min_find = false;
bool is_max_find = false;
for(int i = 0; i < m_fft_x.size(); i++)
{
if(m_fft_x[i] >= m_frequency_x_min && !is_min_find)
{
min_indx = i;
is_min_find = true;
}
if(m_fft_x[i] >= m_frequency_x_max && !is_max_find)
{
max_indx = i;
is_max_find = true;
}
}
int length = max_indx - min_indx + 1;
plot->graph(0)->setData(m_fft_x.mid(min_indx,length), m_fft_y.mid(min_indx,length));
plot->graph(0)->rescaleAxes();
plot->replot();
}
void MainWindow::mouseMove_slot_I(QMouseEvent *event)
{
QCustomPlot *plot = m_plot_i;
//获得鼠标位置处对应的横坐标数据x
double x = plot->xAxis->pixelToCoord(event->pos().x());
if(plot->graph(0)->data().data()->size() != 0)
{
QCPItemTracer * tracer = nullptr;
tracer = m_tracers[0];
tracer->setGraph(plot->graph(0)); //将游标和该曲线图层想连接
tracer->setGraphKey(x); //将游标横坐标设置成刚获得的横坐标数据x
tracer->setInterpolating(true); //游标的纵坐标可以通过曲线数据线性插值自动获得
tracer->updatePosition(); //使得刚设置游标的横纵坐标位置生效
//更新游标说明的内容
double xValue = tracer->position->key();
double yValue = tracer->position->value();
QCPItemText *label = nullptr;
label = m_tracerTexts[0];
if(event->pos().x() > 15 && event->pos().x() < (plot->width()-15)
&& event->pos().y() > 15 && event->pos().y() < (plot->height()-15))
{
label->setVisible(true);
label->setText(QString("[ %1, %2 ]").arg(xValue).arg(yValue));
}
else
{
label->setVisible(false);
}
plot->replot(); //重绘
}
}
void MainWindow::mouseMove_slot_Q(QMouseEvent *event)
{
QCustomPlot *plot = m_plot_q;
//获得鼠标位置处对应的横坐标数据x
double x = plot->xAxis->pixelToCoord(event->pos().x());
if(plot->graph(0)->data().data()->size() != 0)
{
QCPItemTracer * tracer = nullptr;
tracer = m_tracers[1];
tracer->setGraph(plot->graph(0)); //将游标和该曲线图层想连接
tracer->setGraphKey(x); //将游标横坐标设置成刚获得的横坐标数据x
tracer->setInterpolating(true); //游标的纵坐标可以通过曲线数据线性插值自动获得
tracer->updatePosition(); //使得刚设置游标的横纵坐标位置生效
//更新游标说明的内容
double xValue = tracer->position->key();
double yValue = tracer->position->value();
QCPItemText *label = nullptr;
label = m_tracerTexts[1];
if(event->pos().x() > 15 && event->pos().x() < (plot->width()-15)
&& event->pos().y() > 15 && event->pos().y() < (plot->height()-15))
{
label->setVisible(true);
label->setText(QString("[ %1, %2 ]").arg(xValue).arg(yValue));
}
else
{
label->setVisible(false);
}
plot->replot(); //重绘
}
}
void MainWindow::mouseMove_slot_fft_I(QMouseEvent *event)
{
QCustomPlot *plot = m_fft_plot_i;
//获得鼠标位置处对应的横坐标数据x
double x = plot->xAxis->pixelToCoord(event->pos().x());
if(plot->graph(0)->data().data()->size() != 0)
{
QCPItemTracer * tracer = nullptr;
tracer = m_tracers[2];
tracer->setGraph(plot->graph(0)); //将游标和该曲线图层想连接
tracer->setGraphKey(x); //将游标横坐标设置成刚获得的横坐标数据x
tracer->setInterpolating(true); //游标的纵坐标可以通过曲线数据线性插值自动获得
tracer->updatePosition(); //使得刚设置游标的横纵坐标位置生效
//更新游标说明的内容
double xValue = tracer->position->key();
double yValue = tracer->position->value();
QCPItemText *label = nullptr;
label = m_tracerTexts[2];
if(event->pos().x() > 15 && event->pos().x() < (plot->width()-15)
&& event->pos().y() > 15 && event->pos().y() < (plot->height()-15))
{
label->setVisible(true);
label->setText(QString("[ %1, %2 ]").arg(xValue).arg(yValue));
}
else
{
label->setVisible(false);
}
plot->replot(); //重绘
}
}
void MainWindow::mouseMove_slot_fft_Q(QMouseEvent *event)
{
QCustomPlot *plot = m_fft_plot_q;
//获得鼠标位置处对应的横坐标数据x
double x = plot->xAxis->pixelToCoord(event->pos().x());
if(plot->graph(0)->data().data()->size() != 0)
{
QCPItemTracer * tracer = nullptr;
tracer = m_tracers[3];
tracer->setGraph(plot->graph(0)); //将游标和该曲线图层想连接
tracer->setGraphKey(x); //将游标横坐标设置成刚获得的横坐标数据x
tracer->setInterpolating(true); //游标的纵坐标可以通过曲线数据线性插值自动获得
tracer->updatePosition(); //使得刚设置游标的横纵坐标位置生效
//更新游标说明的内容
double xValue = tracer->position->key();
double yValue = tracer->position->value();
QCPItemText *label = nullptr;
label = m_tracerTexts[3];
if(event->pos().x() > 15 && event->pos().x() < (plot->width()-15)
&& event->pos().y() > 15 && event->pos().y() < (plot->height()-15))
{
label->setVisible(true);
label->setText(QString("[ %1, %2 ]").arg(xValue).arg(yValue));
}
else
{
label->setVisible(false);
}
plot->replot(); //重绘
}
}
void MainWindow::mouseMove_slot_fft_C(QMouseEvent *event)
{
QCustomPlot *plot = m_fft_plot_c;
//获得鼠标位置处对应的横坐标数据x
double x = plot->xAxis->pixelToCoord(event->pos().x());
if(plot->graph(0)->data().data()->size() != 0)
{
QCPItemTracer * tracer = nullptr;
tracer = m_tracers[4];
tracer->setGraph(plot->graph(0)); //将游标和该曲线图层想连接
tracer->setGraphKey(x); //将游标横坐标设置成刚获得的横坐标数据x
tracer->setInterpolating(true); //游标的纵坐标可以通过曲线数据线性插值自动获得
tracer->updatePosition(); //使得刚设置游标的横纵坐标位置生效
//更新游标说明的内容
double xValue = tracer->position->key();
double yValue = tracer->position->value();
QCPItemText *label = nullptr;
label = m_tracerTexts[4];
if(event->pos().x() > 15 && event->pos().x() < (plot->width()-15)
&& event->pos().y() > 15 && event->pos().y() < (plot->height()-15))
{
label->setVisible(true);
label->setText(QString("[ %1, %2 ]").arg(xValue).arg(yValue));
}
else
{
label->setVisible(false);
}
plot->replot(); //重绘
}
}
void openFile(const QString &fileName)
{
QFile file(fileName);
if (file.exists()) {
QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
}
}
int MainWindow::writeToFile(QString path, QString text, int recordType)
{
// QString path = QFileDialog::getSaveFileName(this,"保存文件","../untitled.txt","Text files (*.txt)");
// QString path = QDir::cleanPath(QDir::currentPath() + QDir::separator() + QString("data"));
if(path.isEmpty() == false)
{
QFile file; //创建对象
QString suffix;
if(recordType == 0)
{
suffix = "time_for_iq_"+QDateTime::currentDateTime().toString("yyyy-MM-dd_hh_mm_ss")+".txt";
}
else if(recordType == 1)
{
suffix = "time_for_info_"+QDateTime::currentDateTime().toString("yyyy-MM-dd_hh_mm_ss")+".txt";
}
QString filename = path+"/"+suffix;
file.setFileName(filename);
//打开文件,只写
bool isok = file.open(QIODevice::WriteOnly);
if(isok == true)
{
//把读取到的文本写进文件file对象中
//由于文件写函数是qbytearray类型的数据,所以需要在写之前将str转换成bytearray类型
//在qt中有直接转换的函数,toutf8();
file.write(text.toUtf8());
}
else
{
return -1;
}
file.close();
openFile(filename);
}
return 0;
}