本文内容目录
- 需求场景:
- 一、选择控件
- 二、将QCustomPlot库整合到你的Qt项目中
- 1、下载源代码
- 2、创建.pri
- 三、鼠标框选,实现坐标缩放
- 四、曲线拖动
- 1、定位曲线
- 2、移动时改变曲线
- 五、问题的产生与解决
- 1、查看源码
- 2、修改本项目代码
需求场景:
曲线图应该同时具有以下功能点:
1、在画布上进行鼠标框选,实现坐标缩放。
2、可以上下拖动某曲线。
一、选择控件
这里选择QCustomPlot,是一个C++绘图库,可以创建各种类型的绘图,包括散点图、曲线图、直方图、颜色地图、轮廓图等,可以跨平台使用。
以下是QCustomPlot的官方文档:
QCustomPlot官方网站
https://www.qcustomplot.com/
二、将QCustomPlot库整合到你的Qt项目中
1、下载源代码
2、创建.pri
.pri文件的内容添加如下:
HEADERS += \$$PWD/qcustomplot.hSOURCES += \$$PWD/qcustomplot.cpp
将.pri文件,.cpp文件,.h文件放到同一个文件夹下,示例项目为PlotTest。:
并在项目配置文件.pro文件中添加语句:
include(CustomPlot/CustomPlot.pri)
重新构建后,可以看到qcustomplot库已经整合到项目中:
三、鼠标框选,实现坐标缩放
实现代码:mCustomPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
说明:
mCustomPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);setInteractions 函数配置图表的交互方式:QCP::iRangeDrag:启用拖动操作,允许在图表上拖动以平移视图(画布的拖动而非拖动曲线)。
QCP::iRangeZoom:启用缩放操作,允许在图表上进行鼠标滚轮缩放或选择区域以进行缩放。
QCP::iSelectPlottables:启用可选择图表元素的操作。这允许你在图表上单击选择图形元素,以便进行进一步的操作或分析。前两个选项用于框选,后一个选项支持曲线拖动。
mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);setSelectionRectMode 函数配置选择矩形的工作模式:QCP::srmNone:禁用选择矩形,用户无法使用选择矩形进行任何操作。
QCP::srmZoom:启用选择矩形以进行缩放操作,用户可以在图表上创建选择矩形以放大或缩小选定区域。
QCP::srmSelect:启用选择矩形以选择图表中的对象,用户可以在图表上创建选择矩形以选择图表元素,例如曲线。
QCP::srmCustom:自定义选择矩形操作模式,可以根据需要自定义操作。
这里的矩形指的是框选矩形,如下所示:
四、曲线拖动
要实现曲线拖动的思路是,首先要定位,知道拖动的是哪条曲线,其次是当鼠标移动时,要根据鼠标坐标改变曲线。
1、定位曲线
通过信号selectionChangedByUser获得曲线index。
connect(mCustomPlot, &QCustomPlot::selectionChangedByUser, this, &ResultCurves::getSelection);在getSelection槽函数中,可以进行处理,可以用成员变量存储当前用户选中的曲线index
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();
}
五、问题的产生与解决
可以发现,以上两个功能的触发方式都是鼠标左键单击,经过实践,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);
而在mouseReleaseEvent中:
mCustomPlot->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
从而最终可以满足文章开头的需求任务。
欢迎一起讨论!