QCustomPlot系列(3)-用鼠标矩形框进行框选放大、右键平移

2020-7-15 补充:

发现QCustomPlot自带框选放大功能,不需要自己写,

直接启用就好了:

plot->selectionRect()->setPen(QPen(Qt::black,1,Qt::DashLine));//设置选框的样式:虚线
plot->selectionRect()->setBrush(QBrush(QColor(0,0,100,50)));//设置选框的样式:半透明浅蓝
plot->setSelectionRectMode(QCP::SelectionRectMode::srmZoom);

不过使用官方的框选放大功能,也带来一个毛病,就是鼠标左、右、中,三个键都变成了框选放大,失去了拖拽平移功能,这用起来很不爽,我们改一下官方源码,使之同时具备这种功能:1、左键框选时进行放大,2、滚轮按下并拖拽时,可平移曲线,3、右键单击弹出功能菜单。

为实现这3个功能,首先我们要把官方的平移功能,由左键改到右键上,见下文。然后我们再把官方的框选功能限制在左键上,如下图两处修改。齐活儿,enjoy it。

QCustomPlot系列(3)-用鼠标矩形框进行框选放大、右键平移_第1张图片

 

 

 

----------------以下为原文----------------

QCustomPlot原本是不带这个功能的,不过既然有源码,也好改。

原理很简单:1、记录鼠标按下/弹起的像素坐标,并转换为图像坐标,然后把轴的显示范围重新设置一下即可。

2、如果在释放鼠标前按下了ESC键,那么就取消框选放大功能。

先看一下效果:用鼠标画出一个矩形区域,释放鼠标后即可把图像放大到框选区。

QCustomPlot系列(3)-用鼠标矩形框进行框选放大、右键平移_第2张图片QCustomPlot系列(3)-用鼠标矩形框进行框选放大、右键平移_第3张图片

 

由于官方默认左键是平移曲线,我们先把平移功能改到右键(或者滚轮中键,根据你的喜好)上去,直接在这个函数里
void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)改就行了,把Qt::LeftButton改成Qt::RightButton即可。

下面开始实现框选放大功能:

1、在QCustomPlot类中添加private变量:

private:
  QRubberBand *rb;
  QPoint startPos;
  bool cancelRb;

2、直接在h文件中,QCustomPlot类中添加ESC按键处理函数

virtual void QCustomPlot::keyPressEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Escape) {
        cancelRb = true; //记录标志位,以便释放鼠标后不执行缩放代码
        rb->hide();//隐藏选择框
    }
}

3、在QCustomPlot的3个鼠标事件函数添加代码
 

0、在构造函数QCustomPlot::QCustomPlot(QWidget *parent)的初始化列表中添加:
  ,rb(new QRubberBand(QRubberBand::Rectangle, this))
  ,startPos(0, 0)
1、左键按下时,记录坐标起点
    在QCustomPlot::mousePressEvent(QMouseEvent *event)中添加:
    if(event->buttons() & Qt::LeftButton)
    {
        startPos = event->pos();
        cancelRb = false;
        rb->resize(0, 0);
        rb->show();
    }

2、左键按下并移动时,绘制矩形框
    在void QCustomPlot::mouseMoveEvent(QMouseEvent *event)中添加:

    if(event->buttons() & Qt::LeftButton)
    {
        QRect normalRect = QRect(startPos, event->pos()).normalized();//任意两点定义矩形
        rb->setGeometry(normalRect);
    }
3、左键弹起时,记录终点坐标,并把曲线放大到【起点、终点】围成的矩形框中
    在void QCustomPlot::mouseReleaseEvent(QMouseEvent *event)中添加:

    if(event->button() == Qt::LeftButton)
    {
        rb->hide();
        if(!cancelRb)
        {
            QRect normalRect = QRect(startPos, event->pos()).normalized();
            rb->setGeometry(normalRect);
            this->xAxis->setRange(xAxis->pixelToCoord(normalRect.left()),
                                  xAxis->pixelToCoord(normalRect.right()));

            this->yAxis->setRange(yAxis->pixelToCoord(normalRect.bottom()),
                                  yAxis->pixelToCoord(normalRect.top()));
            this->replot();//立即刷新图像
        }
    }

所有代码就这些。

以上代码中需要说明的就3点:

1、框选区使用了QT自带的橡皮筋选区QRubberBand,这玩意在我看来就是个半透明带颜色的QWidget,其实我们完全可以用QWidget来显示鼠标画出的矩形区,只不过有点麻烦而已,需要我们自己设置QWidget的漂亮样式(边框、蓝色半透明等)。总的来看,不如直接用QRubberBand来显示选区方便。

2、记录矩形选区
鼠标按下时记录一次坐标,释放时再记录一次坐标,这两个点构成的矩形就作为选区,只不过这里有个问题,如果你是从左上向右下进行框选这没毛病,如果从右下向左上进行框选,右下点和左上点,这两个点不符合QRec的构造函数形参要求,这样直接用来设置rb->setGeometry(rect);就会显示不出来,因为setGeometry的本质形参是(x,y,w,h),右下点和左上点相减得出的宽度w和高度h都是负的,左下和右上点得出的w+y-等等,只有左上和右下才能得出w+y+。当然这个问题可以程序员自行判断两个点的位置,并重新构造一个合理的x、y、w、h,但是我们没必要费这个劲,QRect::normalized()就是做这个事情的,执行normalized之后,QRect::top/bottom/left/right就是矩形区真正的上下左右。

3、QWidget的像素坐标转换为曲线的XY轴坐标,用的是xAxis->pixelToCoord(xx),反向功能函数为xAxis->coordTopixel(xx)

你可能感兴趣的:(QT/QCustomPlot,QT)