(一)QCustomPlot常见属性设置、多曲线绘制、动态曲线绘制、生成游标、矩形放大等功能实现

系列文章目录

提示:这里是该系列文章的所有文章的目录
第一章: (一)QCustomPlot常见属性设置、多曲线绘制、动态曲线绘制、生成游标、矩形放大等功能实现
第二章: (二)QCustomPlot生成热力图/矩阵颜色图



前言

在最近的项目开发过程中,需要进行大量数据(千万级)的绘制显示,发现Qt+QCustomPlot能够完美解决该需求,在此对这段时间的学习进行下记录总结,下面将新建一个Test项目来进行QCustomPlot的学习。

Test项目主要功能
1.使用定时器进行数据添加模拟
2.界面上同时绘制三条曲线
3.界面动态显示添加的数据
4.生成游标可以跟随鼠标显示相应点位信息
5.鼠标右键实现矩形框选放大功能

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考,完整项目代码展示在第五节。

一、QCustomPlot是什么?

QCustomPlot是一个用于绘图和数据可视化的Qt c++小部件。它没有进一步的依赖性,并且有很好的文档。这个绘图库专注于制作好看、出版质量高的2D绘图、图形和图表,以及为实时可视化应用程序提供高性能。

二、QCustomPlot的下载与安装

QCustomPlot官网链接:https://www.qcustomplot.com/index.php/introduction
下载链接:https://www.qcustomplot.com/index.php/download
我下载好的百度网盘链接:https://pan.baidu.com/s/1sx1NvzlSg_18WKhtsJqdjA
提取码:xxcj
请添加图片描述
下载压缩包后直接解压就行,可以看到以下文件:
请添加图片描述

三、将QCustomPlot源码添加至项目

1.新建一个项目,随后打开项目所在路径
请添加图片描述

2.在该路径下新建一个CustomPlot文件夹,将之前解压获取的qcustomplot.h文件和qcustomplot.cpp文件复制到里面,然后新建一个txt文本文件,里面输入以下内容,完成后将.txt后缀修改为.pri

HEADERS += \
    $$PWD/qcustomplot.h

SOURCES += \
    $$PWD/qcustomplot.cpp

请添加图片描述
请添加图片描述

3.回到QtCreator项目页,点击Test.pro,进行以下修改,完成第三步后可以看到CustomPlot文件夹会自动显示在项目树上
请添加图片描述

四、进行QCustomPlot的提升

1.进入Qt设计师界面,选择一个Widget控件拖动至界面上选中,点击右键–>提升为…,在弹出的窗口上进行输入
请添加图片描述

2.选中更改添加的提升的类,进行如下修改后,点击提升
请添加图片描述

3.编译运行项目,提升成功出现如下界面
请添加图片描述

五、QCustomPlot常见属性设置/代码展示

话不多说,这边直接贴入代码,相关属性设置及功能见代码注释
1.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include "CustomPlot/qcustomplot.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void InitWidget();
    void InitCustomPlot();

private slots:
    void slot_DataTimeOut();
    void slot_CusTimeOut();
    void slot_SelectionChanged();

    void mousePress(QMouseEvent* mevent);
    void mouseMove(QMouseEvent *mevent);
    void mouseRelease(QMouseEvent *mevent);

    void on_action_start_triggered();
    void on_action_stop_triggered();
    void on_action_recovery_triggered();

private:
    Ui::MainWindow *ui;

    QCustomPlot *m_Multichannel;
    QCPItemTracer* tracer;
    QCPItemText* tracerLabel;
    QCPGraph *tracerGraph;
    QRubberBand *rubberBand;
    QPoint rubberOrigin;

    QTimer *dataTimer;
    QTimer *cusTimer;

    int xCount;
    bool chooseFlag;
};
#endif // MAINWINDOW_H

2.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("QCustomPlot");

    InitWidget();
    InitCustomPlot();

}

MainWindow::~MainWindow()
{
    delete m_Multichannel;
    delete ui;
}

void MainWindow::InitWidget()
{
    //初始化一些变量
    xCount = 0;
    chooseFlag = false;
    ui->action_start->setEnabled(true);
    ui->action_stop->setEnabled(false);

    //数据添加定时器
    dataTimer = new QTimer();
    connect(dataTimer,SIGNAL(timeout()),this,SLOT(slot_DataTimeOut()));

    //界面更新定时器
    cusTimer = new QTimer();
    connect(cusTimer,SIGNAL(timeout()),this,SLOT(slot_CusTimeOut()));
}

void MainWindow::InitCustomPlot()
{
    m_Multichannel = new QCustomPlot();
    m_Multichannel = ui->widget;
    //m_Multichannel->axisRect()->setBackground(QBrush(Qt::black));   //设置背景颜色

    for(int i=0;i<3;i++)
    {
        m_Multichannel->addGraph();   //添加数据曲线
        //m_Multichannel->graph(i)->setPen(QPen(Qt::black));   //设置相同颜色的曲线
    }
    //QPen pen;
    //pen.setWidth(1);   //设置选中时的线宽 建议宽度设为1,如果数据量很大,界面会卡顿
    //pen.setColor(Qt::blue);
    //m_Multichannel->graph(0)->setPen(pen);   //这种方式不如下面的方便,屏蔽
    m_Multichannel->graph(0)->setPen(QPen(Qt::black));   //设置曲线颜色
    m_Multichannel->graph(0)->setName("曲线一");          //设置曲线名称
    m_Multichannel->graph(1)->setPen(QPen(Qt::red));
    m_Multichannel->graph(1)->setName("曲线二");
    m_Multichannel->graph(2)->setPen(QPen(Qt::green));
    m_Multichannel->graph(2)->setName("曲线三");
    //m_Multichannel->graph(0)->setBrush(QBrush(QColor(0,0,255,20)));   //在点击对应曲线时 区域变色
    //m_Multichannel->graph(0)->setAntialiasedFill(true);   //设置填充
    //m_Multichannel->graph(0)->setVisible(false);   //设置可见性

    //x轴设置
    QSharedPointer<QCPAxisTickerFixed> intTicker_M(new QCPAxisTickerFixed);
    intTicker_M->setTickStep(1);                                      //设置刻度之间的步长为1
    intTicker_M->setScaleStrategy(QCPAxisTickerFixed::ssMultiples);   //设置缩放策略
    m_Multichannel->xAxis->setTicker(intTicker_M);                    //应用自定义整形ticker,防止使用放大功能时出现相同的x刻度值
    m_Multichannel->xAxis->ticker()->setTickCount(11);                //刻度数量
    m_Multichannel->xAxis->setNumberFormat("f");                      //x轴刻度值格式
    m_Multichannel->xAxis->setNumberPrecision(0);                     //刻度值精度
    m_Multichannel->xAxis->setLabel("数量(n)");                        //设置标签
    m_Multichannel->xAxis->setLabelFont(QFont(font().family(),8));    //设置标签字体大小
    m_Multichannel->xAxis->setRange(0,10,Qt::AlignLeft);              //范围
    m_Multichannel->xAxis->setSubTickLength(0,0);                     //子刻度长度
    m_Multichannel->xAxis->setTickLength(10,5);                       //主刻度长度
    //y轴设置
    m_Multichannel->yAxis->setNumberFormat("f");
    m_Multichannel->yAxis->setNumberPrecision(2);
    m_Multichannel->yAxis->setLabel("距离(m)");
    m_Multichannel->yAxis->setLabelFont(QFont(font().family(),8));
    m_Multichannel->yAxis->setRange(0,5);
    m_Multichannel->yAxis->setTickLength(10,5);

    m_Multichannel->setInteractions(QCP::iNone);   //设置不与鼠标交互
    //m_Multichannel->setInteractions(QCP::iSelectPlottables | QCP::iSelectLegend | QCP::iRangeDrag);   //设置鼠标交互,曲线及图例可点击,可拖动
    m_Multichannel->legend->setVisible(true);                  //设置图例可见
    m_Multichannel->legend->setBrush(QColor(255,255,255,0));   //设置背景透明
	m_Multichannel->axisRect()->insetLayout()->setInsetAlignment(0,Qt::AlignTop|Qt::AlignRight);   //设置图例居右上
    
    //游标
    tracer = new QCPItemTracer(m_Multichannel);       //生成游标
    m_Multichannel->setMouseTracking(true);           //让游标自动随鼠标移动,若不想游标随鼠标动,则禁止
    //tracer->setPen(QPen(QBrush(QColor(Qt::red)),Qt::DashLine));   //虚线游标
    tracer->setPen(QPen(Qt::red));                    //圆圈轮廓颜色
    tracer->setBrush(QBrush(Qt::red));                //圆圈圈内颜色
    tracer->setStyle(QCPItemTracer::tsCircle);        //圆圈
    tracer->setSize(5);
    //tracer->setVisible(false);                      //设置可见性

    //游标说明
    tracerLabel = new QCPItemText(m_Multichannel);                     //生成游标说明
    //tracerLabel->setVisible(false);                                  //设置可见性
    tracerLabel->setLayer("overlay");                                  //设置图层为overlay,因为需要频繁刷新
    tracerLabel->setPen(QPen(Qt::black));                              //设置游标说明颜色
    tracerLabel->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop);   //左上
    tracerLabel->setFont(QFont(font().family(),10));                   //字体大小
    tracerLabel->setPadding(QMargins(4,4,4,4));                        //文字距离边框几个像素
    tracerLabel->position->setParentAnchor(tracer->position);          //设置标签自动随着游标移动

    //选择不同的曲线
    connect(m_Multichannel,SIGNAL(selectionChangedByUser()),this,SLOT(slot_SelectionChanged()));

    //初始化QRubberBand   //矩形放大
    rubberBand = new QRubberBand(QRubberBand::Rectangle,m_Multichannel);
    //连接鼠标事件发出的信号,实现绑定
    connect(m_Multichannel,SIGNAL(mousePress(QMouseEvent*)),this,SLOT(mousePress(QMouseEvent*)));
    connect(m_Multichannel,SIGNAL(mouseMove(QMouseEvent*)),this,SLOT(mouseMove(QMouseEvent*)));
    connect(m_Multichannel,SIGNAL(mouseRelease(QMouseEvent*)),this,SLOT(mouseRelease(QMouseEvent*)));

    //lambda表达式 mouseMoveEvent
    connect(m_Multichannel,&QCustomPlot::mouseMove,[=](QMouseEvent* event){
        if(tracer->graph() == nullptr)
        {
            return;
        }
        if(tracer->graph()->data()->isEmpty())
        {
            return;
        }
        if(tracer->visible())
        {
            if(tracerGraph)
            {
                double x = m_Multichannel->xAxis->pixelToCoord(event->pos().x());
                tracer->setGraphKey(x);             //将游标横坐标设置成刚获得的横坐标数据x
                //tracer->setInterpolating(true);   //自动计算y值,若只想看已有点,不需要这个
                tracer->updatePosition();           //使得刚设置游标的横纵坐标位置生效
                tracerLabel->setText(QString("x:%1\ny:%2").arg(tracer->position->key()).arg(tracer->position->value()));
                m_Multichannel->replot(QCustomPlot::rpQueuedReplot);
            }
        }
    });
}

//多通道界面曲线改变
void MainWindow::slot_SelectionChanged()
{
    for(int i=0;i<3;i++)
    {
        QCPGraph *graph = m_Multichannel->graph(i);
        if(graph == nullptr)
        {
            return;
        }
        QCPPlottableLegendItem *item = m_Multichannel->legend->itemWithPlottable(graph);
        if(item->selected() || graph->selected())   //选中了哪条曲线或者曲线的图例
        {
            tracerGraph = graph;
            if(tracer != nullptr)
            {
                tracer->setGraph(tracerGraph);
            }
            item->setSelected(true);
            QPen pen;
            pen.setWidth(1);   //设置选中时的线宽 建议宽度设为1,如果数据量很大,界面会卡顿
            pen.setColor(Qt::blue);
            graph->selectionDecorator()->setPen(pen);
            graph->setSelection(QCPDataSelection(graph->data()->dataRange()));
        }
    }
}

//添加数据定时器
void MainWindow::slot_DataTimeOut()
{
    m_Multichannel->graph(0)->addData(xCount,1);   //添加数据使用addData
    m_Multichannel->graph(1)->addData(xCount,3);
    m_Multichannel->graph(2)->addData(xCount,5);
    xCount++;
}

//界面更新定时器
void MainWindow::slot_CusTimeOut()
{
    m_Multichannel->xAxis->setRange(0,xCount>10?xCount:10,Qt::AlignLeft);   //xCount代表你的数据量
    m_Multichannel->yAxis->setRange(0,6);   //如果需要y轴自适应数据 就需要获取数据的最小最大值依次填入
    m_Multichannel->replot(QCustomPlot::rpQueuedReplot);   //括号内参数作用是避免重复绘制
}

//鼠标按下槽函数
void MainWindow::mousePress(QMouseEvent* mevent)
{
    if(chooseFlag)
    {
        if(mevent->button() == Qt::RightButton)   //鼠标右键实现放大功能
        {
            rubberOrigin = mevent->pos();
            rubberBand->setGeometry(QRect(rubberOrigin, QSize()));
            rubberBand->show();
        }
    }
}

//鼠标移动槽函数
void MainWindow::mouseMove(QMouseEvent *mevent)
{
    if(chooseFlag)
    {
        if(rubberBand->isVisible())
        {
            rubberBand->setGeometry(QRect(rubberOrigin, mevent->pos()).normalized());
        }
    }
}

//鼠标释放槽函数
void MainWindow::mouseRelease(QMouseEvent *mevent)
{
    if(chooseFlag)
    {
        Q_UNUSED(mevent);
        if(rubberBand->isVisible())
        {
            const QRect zoomRect = rubberBand->geometry();
            int xp1, yp1, xp2, yp2;
            zoomRect.getCoords(&xp1, &yp1, &xp2, &yp2);
            double x1 = m_Multichannel->xAxis->pixelToCoord(xp1);
            double x2 = m_Multichannel->xAxis->pixelToCoord(xp2);
            double y1 = m_Multichannel->yAxis->pixelToCoord(yp1);
            double y2 = m_Multichannel->yAxis->pixelToCoord(yp2);

            m_Multichannel->xAxis->setRange(x1, x2);
            m_Multichannel->yAxis->setRange(y1, y2);

            rubberBand->hide();
            m_Multichannel->replot(QCustomPlot::rpQueuedReplot);
        }
    }
}

void MainWindow::on_action_start_triggered()
{
    //初始化
    xCount = 0;
    for(int i=0;i<3;i++)
    {
        m_Multichannel->graph(i)->data().data()->clear();   //清除当前曲线数据
    }
    m_Multichannel->xAxis->setRange(0,10,Qt::AlignLeft);
    m_Multichannel->yAxis->setRange(0,5);
    m_Multichannel->replot(QCustomPlot::rpQueuedReplot);

    chooseFlag = false;
    dataTimer->start(100);   //设置取数频率
    cusTimer->start(1000);   //设置更新界面频率
    m_Multichannel->setInteractions(QCP::iSelectPlottables | QCP::iSelectLegend);   //设置鼠标交互,曲线及图例可点击

    ui->action_start->setEnabled(false);
    ui->action_stop->setEnabled(true);
}

void MainWindow::on_action_stop_triggered()
{
    chooseFlag = true;   //该标志代表界面更新定时器停止后,可以对界面进行放大操作
    dataTimer->stop();
    cusTimer->stop();
    m_Multichannel->setInteractions(QCP::iSelectPlottables | QCP::iSelectLegend | QCP::iRangeDrag);   //设置鼠标交互,曲线及图例可点击,可拖动

    ui->action_start->setEnabled(true);
    ui->action_stop->setEnabled(false);
}

void MainWindow::on_action_recovery_triggered()
{
    if(chooseFlag)
    {
        m_Multichannel->xAxis->setRange(0,xCount>10?xCount:10,Qt::AlignLeft);
        m_Multichannel->yAxis->setRange(0,6);
        m_Multichannel->replot(QCustomPlot::rpQueuedReplot);
    }
}

3.mianwindow.ui
请添加图片描述

总结

本文标题上的功能,在项目中均有体现。这里也是简单介绍了QCustomPlot的一些属性设置使用,而QCustomPlot还提供了大量能使我们快速便捷地设置属性的函数和方法,这些就需要我们持续的挖掘学习,加油!

下一篇主要讲述了QCustomPlot中的QCPColorMap热力图相关知识
本系列文章下一篇:(二)QCustomPlot生成热力图/矩阵颜色图


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考博客:QCustomPlot基础教程(一)——QCustomPlot的安装及基础实例

  • 39
    点赞
  • 352
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值