PC 表格控件 C++ QT QCustomPlot 实时折现图更新 (CLion Cmake)

PC 表格控件 C++ QT QCustomPlot 实时折线图更新 (CLion Cmake)

前言

近日,工作中需要在PC端实现实时数据的图表展示。并未接触过PC的图表控件,因此记录一下。

功能包括:

1.图表拖拽和缩放

2.实时更新

3.点击标注

4.坐标轴方向缩放

准备工具

1 . QT5

这个我用的是5.15.2版本,下载慢可能还需要改镜像 比较麻烦 可以自己去网上搜一下

2 . QCustomplot

下载第一个 Full package

开始

Clion打开qt程序需要配置和CMakeLists 先把下载来的qcustomplot.cpp 、qcustomplot.h放在项目根目录 在CMakeLists中添加配置。

cmakelists 复制代码
set(CMAKE_PREFIX_PATH "X:/Qt/5.15.2/mingw81_64")
·
·
·
add_executable(QCustomPlotTest main.cpp  
.
qcustomplot.cpp  
qcustomplot.h  
)

初始化图表

init 复制代码
plot = new QCustomPlot(this);  
setCentralWidget(plot);

添加曲线(自定义一些颜色 Label 宽度等)

addGraph 复制代码
plot->addGraph();  
plot->xAxis->setLabel("X");  
plot->yAxis->setLabel("Y");  
QPen pen;
pen.setColor(QColor(255, 0, 0)); 
pen.setWidth(1);  
plot->graph(0)->setPen(pen); 

图像的拖拽和缩放

这个其实很简单 QCustomPlot 已经封装好了 只需要设置交互就行了

setInteractions 复制代码
plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iMultiSelect);

实时更新

实时更新就是不断往曲线的点集数据结构里添加数据,添加完了后再重绘曲线,也需要调整坐标轴范围。

updatePlot 复制代码
void updatePlot(double val) {
    // 添加新的数据点到 xData 和 yData 中
    xData.append(x);
    x += 0.1;
    yData.append(val);

    // 如果 yData 为空,将最小值和最大值设置为 val
    if (yData.isEmpty()) {
        minValue = val;
        maxValue = val;
    } else {
        // 如果 val 小于最小值,更新最小值并调整 y 轴范围
        if (val < minValue) {
            minValue = val;
            plot->yAxis->setRange(minValue - 0.1, maxValue + 0.1); // 调整 y 轴范围
        }
        // 如果 val 大于最大值,更新最大值并调整 y 轴范围
        if (val > maxValue) {
            maxValue = val;
            plot->yAxis->setRange(minValue - 0.1, maxValue + 0.1); // 调整 y 轴范围
        }
    }

    // 设置曲线的数据源为 xData 和 yData
    plot->graph(0)->setData(xData, yData);

    // 调整 x 轴的范围
    plot->xAxis->setRange(0, x);

    // 重新绘制曲线
    plot->replot();
}

点击标注

点击标注需要用到Qt的信号槽 和一些QCPItem 分别是 QCPItemLine和QCPItemText

QCPItemLine 可以在 QCustomPlot 图形上绘制一条直线。可以指定线的起点和终点坐标,以及线的样式、颜色等属性。用于在图形上标记特定的数据点、绘制参考线等。

QCPItemText 可以在图形上添加自定义文本。可以指定文本的位置、内容、字体、颜色等属性。通常用于标记图形中的关键信息或添加注释

比较麻烦的是设置QCPItemText的坐标位置 我这里计算了刻度线之间的间隔, 令x、y坐标分别加上二分之一的间隔 这样不管是放大或者缩小图表时候都可以使标注显示在一个较好的位置

QCPItemLine我把范围+ -10000也是为了在缩放图表时候可以一直显示参考线

init 复制代码
QCPItemLine *xLine = nullptr;  
QCPItemLine *yLine = nullptr;
connect(plot, &QCustomPlot::plottableClick, this, &QCustomPlotTest::onPlotClick);
onPlotClick 复制代码
void QCustomPlotTest::onPlotClick(QCPAbstractPlottable *plottable, int dataIndex, QMouseEvent *event) {
    Q_UNUSED(event)

    // 检查是否存在有效的绘图区域
    if (!plot)
        return;

    // 移除之前的标记线和文本
    if (plot->itemCount() > 0) {
        plot->removeItem(xLine);
        plot->removeItem(yLine);
        plot->removeItem(textLabel);
    }

    // 获取点击数据点的 x 和 y 坐标
    double xCoordinate = plot->graph(0)->dataMainKey(dataIndex);
    double yCoordinate = plot->graph(0)->dataMainValue(dataIndex);

    // 获取 y 和 x 轴的刻度线
    QVector<double> yTicks = plot->yAxis->tickVector();
    QVector<double> xTicks = plot->xAxis->tickVector();

    // 计算刻度线之间的间隔
    double yTickInterval = yTicks.size() >= 2 ? yTicks[1] - yTicks[0] : 0.0;
    double xTickInterval = xTicks.size() >= 2 ? xTicks[1] - xTicks[0] : 0.0;

    // 创建文本标签
    textLabel = new QCPItemText(plot);
    textLabel->setPositionAlignment(Qt::AlignBottom);
    textLabel->position->setType(QCPItemPosition::ptPlotCoords);
    textLabel->position->setCoords(xCoordinate + xTickInterval / 2, yCoordinate + yTickInterval / 2);
    textLabel->setFont(QFont("Times New Roman", 5));
    textLabel->setText(QString("(%1, %2)").arg(xCoordinate).arg(yCoordinate));
    textLabel->setPadding(QMargins(5, 4, 5, 4));

    // 设置文本标签的背景颜色和文本颜色
    QBrush backgroundBrush;
    backgroundBrush.setColor(Qt::black);
    backgroundBrush.setStyle(Qt::SolidPattern);
    textLabel->setBrush(backgroundBrush);
    textLabel->setColor(Qt::white);

    // 创建垂直和水平虚线以标记数据点
    QPen linePen;
    linePen.setColor(Qt::gray);
    linePen.setWidth(1);
    linePen.setStyle(Qt::DashLine);

    // 创建垂直线
    xLine = new QCPItemLine(plot);
    xLine->start->setCoords(xCoordinate, plot->yAxis->range().lower - 10000);
    xLine->end->setCoords(xCoordinate, plot->yAxis->range().upper + 10000);
    xLine->setPen(linePen);

    // 创建水平线
    yLine = new QCPItemLine(plot);
    yLine->start->setCoords(plot->xAxis->range().lower - 10000, yCoordinate);
    yLine->end->setCoords(plot->xAxis->range().upper + 10000, yCoordinate); 
    yLine->setPen(linePen);
    
    // 重新绘制图形
    plot->replot(); 
    
    // 启动一个计时器,定时清除标记线和文本
    timer->start(2000);

坐标轴方向缩放

这个是可以用监听Qt的horizontalSlider和verticalSlider滑动控件,当其中的值发生变化时触发该函数

js 复制代码
connect(ui->horizontalSlider, &QSlider::valueChanged, this, &QCustomPlotTest::onSliderValueChanged);  
connect(ui->verticalSlider, &QSlider::valueChanged, this, &QCustomPlotTest::onVerSliderValueChanged);
onVerSliderValueChanged 复制代码
void QCustomPlotTest::onVerSliderValueChanged(int value) {
    // 将滑块的值转换为浮点数的缩放因子
    double scaleFactor = static_cast<double>(value) / 100.0;

    // 如果 x 不等于 0(假设 x 是某个变量的值)
    if (x != 0) {
        // 根据缩放因子调整 y 轴的范围,以保持数据中心不变
        double newMinValue = (minValue + maxValue) / 2 - (maxValue - minValue) / (2 * scaleFactor);
        double newMaxValue = (minValue + maxValue) / 2 + (maxValue - minValue) / (2 * scaleFactor);

        // 设置 y 轴的新范围
        plot->yAxis->setRange(newMinValue, newMaxValue);
        plot->replot(); // 重新绘制图形
    } else {
        // 如果 x 等于 0,将 y 轴范围设置为固定值
        plot->yAxis->setRange(0, 5.0 / scaleFactor);
        plot->replot(); // 重新绘制图形
    }
}
相关推荐
ChoSeitaku3 分钟前
12.重复内容去重|添加日志|部署服务到Linux上(C++)
linux·c++·windows
挣扎与觉醒中的技术人8 分钟前
网络安全入门持续学习与进阶路径(一)
网络·c++·学习·程序人生·安全·web安全
OTWOL1 小时前
【C++编程入门基础(一)】
c++·算法
宇寒风暖1 小时前
侯捷 C++ 课程学习笔记:内存管理与工具应用
c++·笔记·学习
Smile丶凉轩2 小时前
数据库面试知识点总结
数据库·c++·mysql
Want5952 小时前
C/C++跳动的爱心
c语言·开发语言·c++
水瓶丫头站住2 小时前
Qt中QDockWidget的使用方式
开发语言·qt
laimaxgg2 小时前
Qt常用控件之数字显示控件QLCDNumber
开发语言·c++·qt·qt5·qt6.3
蓝天扶光2 小时前
c++贪心系列
开发语言·c++
Alidme3 小时前
cs106x-lecture14(Autumn 2017)-SPL实现
c++·学习·算法·codestepbystep·cs106x