QT应用编程: 使用qcustomplot显示动态曲线、设计心电图显示页面

2022-01-07 14:47:21 浏览数 (1)

一、环境介绍

操作系统: win10 64位

QT版本: QT5.12.6

编译器: MinGW 32

二、功能介绍

软件端接收设备上传的心电数据、运动数据、体温数据进行处理、存储显示。

完整项目源码下载链接: https://download.csdn.net/download/xiaolong1126626497/18607424

三、核心代码

3.1 widget.cpp

代码语言:javascript复制
#include "widget.h"
#include "ui_widget.h"

#define AppFontName "Microsoft YaHei"
#define AppFontSize 9

#define TextColor QColor(255,255,255)
#define Plot_NoColor QColor(0,0,0,0)

//曲线1的颜色
#define HeartRate_Plot_DotColor QColor(236,110,0)
#define HeartRate_Plot_LineColor QColor(246,98,0)
#define HeartRate_Plot_BGColor QColor(246,98,0,80)

//曲线2的颜色
#define HeartRate_Plot_DotColor_2 Qt::blue
#define HeartRate_Plot_LineColor_2 Qt::blue
#define HeartRate_Plot_BGColor_2 Qt::blue

#define TextWidth 1
#define LineWidth 2
#define DotWidth 5

//一个刻度里的小刻度数量--太小的话显示的时间会重叠
#define HeartRate_Plot_Count 5
//Y轴最大范围值
#define HeartRate_Plot_MaxY 3000

/*
 * 设置QT界面的样式
*/
void Widget::SetStyle(const QString &qssFile) {
    QFile file(qssFile);
    if (file.open(QFile::ReadOnly)) {
        QString qss = QLatin1String(file.readAll());
        qApp->setStyleSheet(qss);
        QString PaletteColor = qss.mid(20,7);
        qApp->setPalette(QPalette(QColor(PaletteColor)));
        file.close();
    }
    else
    {
        qApp->setStyleSheet("");
    }
}

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    /*服务器线程*/
    //开始信号
    connect(this,SIGNAL(StartServerThread()),&tcp_server_class,SLOT(run()));
    //日志信号
    connect(&tcp_server_class,SIGNAL(LogSend(QString)),this,SLOT(Log_Display(QString)));
    //移动到线程
    tcp_server_class.moveToThread(&tcp_server_thread);
    tcp_server_thread.start(); //启动线程
    StartServerThread(); //创建服务器

    this->setWindowTitle("健康监控管家");

    //波形图界面初始化
    InitForm();
    InitPlot();
    HeartRate_InitPlot();
    HeartRate_LoadPlot();
    SetStyle(":/blue.css");
    //开始加载数据
    plot_timer->start(100);
}

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

//日志显示
void Widget::Log_Display(QString text)
{
    QPlainTextEdit *plainTextEdit_log=ui->plainTextEdit_log;
    //设置光标到文本末尾
    plainTextEdit_log->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
    //当文本数量超出一定范围就清除
    if(plainTextEdit_log->toPlainText().size()>1024*4)
    {
        plainTextEdit_log->clear();
    }
    plainTextEdit_log->insertPlainText(text);
    //移动滚动条到底部
    QScrollBar *scrollbar = plainTextEdit_log->verticalScrollBar();
    if(scrollbar)
    {
        scrollbar->setSliderPosition(scrollbar->maximum());
    }
}

//查看服务器状态
void Widget::on_toolButton_server_stat_clicked()
{
    QString text="服务器IP地址列表:n";
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    for(int i=0;i<list.count();i  )
    {
        QHostAddress addr=list.at(i);
        if(addr.protocol() == QAbstractSocket::IPv4Protocol)
        {
          text =addr.toString() "n";
        }
    }
    text ="服务器端口号:8888n";
    if(ClientSocket)
    {
        if(ClientSocket->socketDescriptor()==-1)
        {
            text ="设备未连接n";
        }
        else
        {
            text ="设备连接成功n";
        }
    }
    else
    {
        text ="设备未连接n";
    }
    QMessageBox::about(this,"状态信息",text);
}

//窗口关闭事件
void Widget::closeEvent(QCloseEvent *event)
{
    tcp_server_thread.quit();
    tcp_server_thread.wait();
}

void Widget::InitForm()
{
    //初始化随机数种子
    QTime time = QTime::currentTime();
    qsrand(time.msec()   time.second() * 1000);

    //初始化动态曲线定时器
    plot_timer = new QTimer(this);
    connect(plot_timer, SIGNAL(timeout()), this, SLOT(HeartRate_LoadPlot()));

    plots.append(ui->plot2);
}

void Widget::InitPlot()
{
    //设置纵坐标名称
    plots.at(0)->yAxis->setLabel("心电数据(单位:%)");
    //设置纵坐标范围
    plots.at(0)->yAxis->setRange(0, HeartRate_Plot_MaxY);
    //设置支持鼠标移动缩放波形界面
    plots.at(0)->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
    //设置背景颜色
#if 1
    foreach (QCustomPlot *plot, plots)
    {
        //设置字体大小
        QFont font = QFont(AppFontName, AppFontSize - 2);
        plot->legend->setFont(font);
        plot->xAxis->setLabelFont(font);
        plot->yAxis->setLabelFont(font);
        plot->xAxis->setTickLabelFont(font);
        plot->yAxis->setTickLabelFont(font);

        //设置坐标颜色/坐标名称颜色
        plot->yAxis->setLabelColor(TextColor);
        plot->xAxis->setTickLabelColor(TextColor);
        plot->yAxis->setTickLabelColor(TextColor);
        plot->xAxis->setBasePen(QPen(TextColor, TextWidth));
        plot->yAxis->setBasePen(QPen(TextColor, TextWidth));
        plot->xAxis->setTickPen(QPen(TextColor, TextWidth));
        plot->yAxis->setTickPen(QPen(TextColor, TextWidth));
        plot->xAxis->setSubTickPen(QPen(TextColor, TextWidth));
        plot->yAxis->setSubTickPen(QPen(TextColor, TextWidth));

        //设置画布背景色
        QLinearGradient plotGradient;
        plotGradient.setStart(0, 0);
        plotGradient.setFinalStop(0, 350);
        plotGradient.setColorAt(0, QColor(80, 80, 80));
        plotGradient.setColorAt(1, QColor(50, 50, 50));
        plot->setBackground(plotGradient);

        //设置坐标背景色
        QLinearGradient axisRectGradient;
        axisRectGradient.setStart(0, 0);
        axisRectGradient.setFinalStop(0, 350);
        axisRectGradient.setColorAt(0, QColor(80, 80, 80));
        axisRectGradient.setColorAt(1, QColor(30, 30, 30));
        plot->axisRect()->setBackground(axisRectGradient);

        //设置图例提示位置及背景色
        plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop | Qt::AlignRight);
        plot->legend->setBrush(QColor(255, 255, 255, 200));
        plot->replot();
    }
#endif
}


void Widget::HeartRate_InitPlot()
{
    plots.at(0)->addGraph();

    plots.at(0)->graph(0)->setName("心电数据1");
    plots.at(0)->graph(0)->setPen(QPen(HeartRate_Plot_LineColor, LineWidth));
    plots.at(0)->graph(0)->setScatterStyle(
        QCPScatterStyle(QCPScatterStyle::ssCircle,
                        QPen(HeartRate_Plot_DotColor, LineWidth),
                        QBrush(HeartRate_Plot_DotColor), DotWidth));
    //设置动态曲线的横坐标格式及范围
    plots.at(0)->xAxis->setTickLabelType(QCPAxis::ltDateTime);
    plots.at(0)->xAxis->setDateTimeFormat("HH:mm:ss");
    plots.at(0)->xAxis->setAutoTickStep(true);
    plots.at(0)->xAxis->setTickStep(0.5);
    plots.at(0)->xAxis->setRange(0, HeartRate_Plot_Count, Qt::AlignRight);

    plots.at(0)->addGraph();//相当于添加一条新的曲线
    plots.at(0)->graph(1)->setName("心电数据2");
    plots.at(0)->graph(1)->setPen(QPen(HeartRate_Plot_LineColor_2, LineWidth));
    plots.at(0)->graph(1)->setScatterStyle(
        QCPScatterStyle(QCPScatterStyle::ssCircle,
                        QPen(HeartRate_Plot_DotColor_2, LineWidth),
                        QBrush(HeartRate_Plot_DotColor_2), DotWidth));


    //设置是否需要显示曲线的图例说明
    foreach (QCustomPlot *plot, plots)
    {
        plot->legend->setVisible(true);
        plot->replot();
    }


    //得到数据指针
    mData_0 = plots.at(0)->graph(0)->data();
    mData_1 = plots.at(0)->graph(1)->data();
}

void addToDataBuffer(QCPDataMap *mData,double x, double y)
{
    QCPData newData;

    newData.key = x;
    newData.value = y;

    mData->insert(x, newData);
}


//加载曲线数据
void Widget::HeartRate_LoadPlot()
{
    int i;
    bool flag=false;

    for(i=0;i<5;i  )
    {
        //得到秒单位的时间
        HeartRate_plot_key = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0;
        //心电数据1
        HeartRate_plot_value=uart_queue_data.read_queueA();
        if(HeartRate_plot_value>0)
        {
            flag=true;
            addToDataBuffer(mData_0,HeartRate_plot_key,HeartRate_plot_value);
        }

        //心电数据2
        HeartRate_plot_value=uart_queue_data.read_queueB();
        if(HeartRate_plot_value>0)
        {
            flag=true;
            addToDataBuffer(mData_1,HeartRate_plot_key,HeartRate_plot_value);
        }
    }
    if(flag)
    {
        plots.at(0)->xAxis->setRange(HeartRate_plot_key, HeartRate_Plot_Count , Qt::AlignRight);
        plots.at(0)->rescaleAxes(false);  //设置图表完全可见
        plots.at(0)->replot();

    }

    /*
    A:心电数据1,B:新电数据2,C:运动步数,D:运动距离,E:体表温度
    例如: "A:1633215,B:1833215,C:45,D:28,E:66.55"
    */
    int val=uart_queue_data.read_queueC();
    if(val>0)
    {
        ui->lcdNumber_bumber->display(val);
    }

    val=uart_queue_data.read_queueD();
    if(val>0)
    {
        ui->lcdNumber_len->display(val);
    }

    double tmp_val=uart_queue_data.read_queueE();
    if(tmp_val>0)
    {
        ui->lcdNumber_temp->display(tmp_val);
    }
}

void Widget::on_toolButton_src_data_clicked()
{
    ui->stackedWidget->setCurrentIndex(0);
}

void Widget::on_toolButton_image_data_clicked()
{
    ui->stackedWidget->setCurrentIndex(1);
}

void Widget::on_toolButton_clear_clicked()
{
    mData_0->clear();
    mData_1->clear();
}

3.2 widget.h

代码语言:javascript复制
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "server.h"
#include <QPlainTextEdit>
#include <QTextCursor>
#include <QScrollBar>
#include <QPalette>

#include "qcustomplot.h"
#include "smoothcurvecreator.h"


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void SetStyle(const QString &qssFile);
    QThread tcp_server_thread; //服务器工作线程
    TCPServer tcp_server_class;

    //绘制实时曲线
    QTimer *plot_timer;
    QList <QCustomPlot *> plots;

    double HeartRate_plot_key;
    unsigned int HeartRate_plot_value;

    //曲线数据点缓冲区
    QCPDataMap *mData_0;
    QCPDataMap *mData_1;

signals:
    void StartServerThread(); //启动服务器线程
private slots:
    void Log_Display(QString text);
    void on_toolButton_server_stat_clicked();
    void HeartRate_InitPlot();
    void HeartRate_LoadPlot();
    void InitPlot();
    void InitForm();
    void on_toolButton_src_data_clicked();

    void on_toolButton_image_data_clicked();

    void on_toolButton_clear_clicked();

protected:
    void closeEvent(QCloseEvent *event); //窗口关闭
private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

0 人点赞