• QCustomPlot实现曲线拖拽


    需求场景:

    曲线图应该同时具有以下功能点:
    1、在画布上进行鼠标框选,实现坐标缩放。
    2、可以上下拖动某曲线。

    在这里插入图片描述

    一、选择控件

    这里选择QCustomPlot,是一个C++绘图库,可以创建各种类型的绘图,包括散点图、曲线图、直方图、颜色地图、轮廓图等,可以跨平台使用。

    以下是QCustomPlot的官方文档:
    QCustomPlot官方网站
    https://www.qcustomplot.com/

    二、将QCustomPlot库整合到你的Qt项目中

    1、下载源代码

    在这里插入图片描述

    2、创建.pri

    .pri文件的内容添加如下:

    HEADERS += \
        $$PWD/qcustomplot.h
    
    SOURCES += \
        $$PWD/qcustomplot.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5

    将.pri文件,.cpp文件,.h文件放到同一个文件夹下,示例项目为PlotTest。:
    在这里插入图片描述
    并在项目配置文件.pro文件中添加语句:

    include(CustomPlot/CustomPlot.pri)
    
    • 1

    重新构建后,可以看到qcustomplot库已经整合到项目中:
    在这里插入图片描述

    三、鼠标框选,实现坐标缩放

    实现代码:
    
    mCustomPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
    mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
    
    • 1
    • 2
    • 3
    • 4

    说明:

    mCustomPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
    
    setInteractions 函数配置图表的交互方式:
    
    QCP::iRangeDrag:启用拖动操作,允许在图表上拖动以平移视图(画布的拖动而非拖动曲线)。
    QCP::iRangeZoom:启用缩放操作,允许在图表上进行鼠标滚轮缩放或选择区域以进行缩放。
    QCP::iSelectPlottables:启用可选择图表元素的操作。这允许你在图表上单击选择图形元素,以便进行进一步的操作或分析。
    
    前两个选项用于框选,后一个选项支持曲线拖动。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
    
    setSelectionRectMode 函数配置选择矩形的工作模式:
    
    QCP::srmNone:禁用选择矩形,用户无法使用选择矩形进行任何操作。
    QCP::srmZoom:启用选择矩形以进行缩放操作,用户可以在图表上创建选择矩形以放大或缩小选定区域。
    QCP::srmSelect:启用选择矩形以选择图表中的对象,用户可以在图表上创建选择矩形以选择图表元素,例如曲线。
    QCP::srmCustom:自定义选择矩形操作模式,可以根据需要自定义操作。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里的矩形指的是框选矩形,如下所示:
    在这里插入图片描述

    四、曲线拖动

    要实现曲线拖动的思路是,首先要定位,知道拖动的是哪条曲线,其次是当鼠标移动时,要根据鼠标坐标改变曲线。

    1、定位曲线

    通过信号selectionChangedByUser获得曲线index。

    connect(mCustomPlot, &QCustomPlot::selectionChangedByUser, this, &ResultCurves::getSelection);
    
    在getSelection槽函数中,可以进行处理,可以用成员变量存储当前用户选中的曲线index
    
    • 1
    • 2
    • 3
    2、移动时改变曲线

    重写鼠标移动事件mouseMoveEvent。

    void ResultCurves::mouseMoveEvent(QMouseEvent *event)
    {
    	//获取鼠标的本地窗口坐标
        double x = event->pos().x();
        double y = event->pos().y();
    	//将鼠标指针的像素坐标转换为图表上的实际坐标
        double xCurve = mCustomPlot->xAxis->pixelToCoord(x);
        double yCurve = mCustomPlot->yAxis->pixelToCoord(y);
    	//获取当前图表显示的y轴最大坐标,这里用于限制曲线的移动坐标范围
        double yMax = mCustomPlot->yAxis->range().upper;
        double yMin = mCustomPlot->yAxis->range().lower;
    
        mPosX = xCurve;
        mPosY = yCurve;
    
        if(mPosY > yMax){
            mPosY = yMax;
        }
    
        if(mPosY < yMin){
            mPosY = yMin;
        }
    	//当目标曲线被选中时,在drawThresholdLine中进行曲线的重新绘制
        if(mIsThresholdSelected)
        {
            drawThresholdLine(mPosY);
        }
    }
    
    void ResultCurves::drawThresholdLine(double yValue)
    {
    	//在QCustomPlot对象和mGraphList曲线列表中删除目标曲线
        mCustomPlot->removeGraph(mGraphList.size() - 1);
        mGraphList.removeLast();
        //新增更新曲线
        QVector<double> temp;
        for(int i=0; i<mCurveList.begin().value().size(); i++)
        {
            temp.append(yValue);
        }
    
        addCurve(mGraphList.size(),mXValues,temp);
        mCustomPlot->replot();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    五、问题的产生与解决

    可以发现,以上两个功能的触发方式都是鼠标左键单击,经过实践,qcustomplot不能区分鼠标左键单击后是执行框选还是拖动,即使是在mousepressevent中判断是否选中目标曲线,若选中则mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmNone);(禁用矩形),也不能使两个功能共存。

    1、查看源码

    发现在QCustomPlot::mouseMoveEvent中,调用到一个函数processPointSelection:
    在这里插入图片描述
    该函数处理鼠标事件,特别是点选操作,也仅在QCustomPlot::mouseMoveEvent中调用。如果发生了选择状态的更改(selectionStateChanged 为 true),则发出 selectionChangedByUser 信号。
    所以一个简单直接的思路是,当我想框选时,不调用该函数,不进行点选操作;当我想拖动时,调用该函数,发出 selectionChangedByUser 信号。
    因此增加一个bool变量和接口:在这里插入图片描述
    在这里插入图片描述

    2、修改本项目代码

    在以上更改后,在我们自定义类的mousePressEvent中,当选中曲线index为目标曲线index时:

    mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmNone);
    mCustomPlot->setHoverPicked(false);
    
    • 1
    • 2

    而在mouseReleaseEvent中:

    mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
    
    • 1

    从而最终可以满足文章开头的需求任务。

    欢迎一起讨论!

  • 相关阅读:
    YOLOv8改进实战 | 更换主干网络Backbone(五)之2023最新轻量化主干网络VanillaNet,深度学习中极简主义的力量
    计算机视觉(CV)技术的优势和挑战
    【论文笔记】Dynamic Convolution: Attention over Convolution Kernels
    【机器学习】数据清洗之识别重复点
    第6章 字符串操作
    大学生网页作业成品——基于HTML网上书城项目的设计与实现
    文件管理功能重构,MeterSphere开源持续测试平台v2.1.0发布
    华为云IOT平台设备获取api调用笔记
    容器资料: Docker和Singularity
    quartz笔记
  • 原文地址:https://blog.csdn.net/qq_43262059/article/details/133815400