zoukankan      html  css  js  c++  java
  • Qt QChart 自定义qChartView(重写鼠标事件)完美实现缩放与平移(新增android下手势缩放实现)

    功能

    实现QtCharts曲线图移动和缩放:

    1. 按住鼠标左键拖动曲线可移动曲线;
    2. 滚动鼠标滚轮实现图形X轴方向的缩放;
    3. 按住Ctrl,滚动鼠标滚轮实现图形Y轴方向的缩放;
    4. 按鼠标右键恢复图形初始状态;
    5. 缩放过程以鼠标当前位置为缩放中心;
    6. 鼠标移动过程中会在左上角显示当前坐标。

    实现

    继承QChartView,主要重新实现鼠标事件和键盘事件。

    1. 移动图形利用QChart的scroll函数;
      void scroll(qreal dx, qreal dy, const QRectF &rect = QRectF());
      鼠标按下时,记录按下状态,并记录当前坐标位置,在移动事件内计算鼠标移动的距离,以此设置图形滚动的距离,即可实现移动
    2. 缩放则设置当前坐标轴的显示范围;
      void setRange(const QVariant &min, const QVariant &max);

    代码

    .cpp文件

    实现移动

     1 void ChartView::mousePressEvent(QMouseEvent *event)
     2 {
     3     if (event->button() == Qt::LeftButton)
     4     {
     5         m_lastPoint = event->pos();
     6         m_isPress = true;
     7     }
     8 }
     9 
    10 void ChartView::mouseMoveEvent(QMouseEvent *event)
    11 {
    12     if (!m_coordItem)
    13     {
    14         m_coordItem = new QGraphicsSimpleTextItem(this->chart());
    15         m_coordItem->setZValue(5);
    16         m_coordItem->setPos(100, 60);
    17         m_coordItem->show();
    18     }
    19     const QPoint curPos = event->pos();
    20     QPointF curVal = this->chart()->mapToValue(QPointF(curPos));
    21     QString coordStr = QString("X = %1, Y = %2").arg(curVal.x()).arg(curVal.y());
    22     m_coordItem->setText(coordStr);
    23 
    24     if (m_isPress)
    25     {
    26         QPoint offset = curPos - m_lastPoint;
    27         m_lastPoint = curPos;
    28         if (!m_alreadySaveRange)
    29         {
    30             this->saveAxisRange();
    31             m_alreadySaveRange = true;
    32         }
    33         this->chart()->scroll(-offset.x(), offset.y());
    34     }
    35 }
    36 
    37 void ChartView::mouseReleaseEvent(QMouseEvent *event)
    38 {
    39     m_isPress = false;
    40     if (event->button() == Qt::RightButton)
    41     {
    42         if (m_alreadySaveRange)
    43         {
    44             this->chart()->axisX()->setRange(m_xMin, m_xMax);
    45             this->chart()->axisY()->setRange(m_yMin, m_yMax);
    46         }
    47     }
    48 }
    49 
    50 //保存原始位置
    51 void ChartView::saveAxisRange()
    52 {
    53     QValueAxis *axisX = dynamic_cast<QValueAxis*>(this->chart()->axisX());
    54     m_xMin = axisX->min();
    55     m_xMax = axisX->max();
    56     QValueAxis *axisY = dynamic_cast<QValueAxis*>(this->chart()->axisY());
    57     m_yMin = axisY->min();
    58     m_yMax = axisY->max();
    59 }

    实现缩放

     1 void ChartView::wheelEvent(QWheelEvent *event)
     2 {
     3    const QPoint curPos = event->pos();
     4    QPointF curVal = this->chart()->mapToValue(QPointF(curPos));
     5 
     6    if (!m_alreadySaveRange)
     7    {
     8        this->saveAxisRange();
     9        m_alreadySaveRange = true;
    10    }
    11    const double factor = 1.5;//缩放比例
    12    if (m_ctrlPress)
    13    {//Y轴
    14        QValueAxis *axisY = dynamic_cast<QValueAxis*>(this->chart()->axisY());
    15        const double yMin = axisY->min();
    16        const double yMax = axisY->max();
    17        const double yCentral = curVal.y();
    18 
    19        double bottomOffset;
    20        double topOffset;
    21        if (event->delta() > 0)
    22        {//放大
    23            bottomOffset = 1.0 / factor * (yCentral - yMin);
    24            topOffset = 1.0 / factor * (yMax - yCentral);
    25        }
    26        else
    27        {//缩小
    28            bottomOffset = 1.0 * factor * (yCentral - yMin);
    29            topOffset = 1.0 * factor * (yMax - yCentral);
    30        }
    31 
    32        this->chart()->axisY()->setRange(yCentral - bottomOffset, yCentral + topOffset);
    33    }
    34    else
    35    {//X轴
    36        QValueAxis *axisX = dynamic_cast<QValueAxis*>(this->chart()->axisX());
    37        const double xMin = axisX->min();
    38        const double xMax = axisX->max();
    39        const double xCentral = curVal.x();
    40 
    41        double leftOffset;
    42        double rightOffset;
    43        if (event->delta() > 0)
    44        {//放大
    45            leftOffset = 1.0 / factor * (xCentral - xMin);
    46            rightOffset = 1.0 / factor * (xMax - xCentral);
    47        }
    48        else
    49        {//缩小
    50            leftOffset = 1.0 * factor * (xCentral - xMin);
    51            rightOffset = 1.0 * factor * (xMax - xCentral);
    52        }
    53        this->chart()->axisX()->setRange(xCentral - leftOffset, xCentral + rightOffset);
    54    }
    55 }
    56 }

    以下为Qt Android下使用手势实现Qchart的缩放

    要使用手势,先在构造函数中注册允许使用手势

    1 //this->setAttribute(Qt::WA_AcceptTouchEvents);              //设置接收触摸事件
    2 grabGesture(Qt::PinchGesture);                                //这里只grabGesture了PinchGesture
     1 //监听事件类型
     2 bool ChartView::event(QEvent *event)
     3 {
     4     switch(event->type())
     5     {
     6 //    case QEvent::TouchBegin:
     7 //        //accepting touch begin allows us to get touch updates
     8 //        return true;
     9 //        break;
    10     case QEvent::Gesture:               //如果是手势事件就交给手势事件处理
    11         return gestureEvent(static_cast<QGestureEvent*>(event));
    12         break;
    13     default:                            //默认为鼠标事件
    14         break;
    15     }
    16     return QWidget::event(event);
    17 }
    18 
    19 //处理手势事件
    20 bool ChartView::gestureEvent(QGestureEvent *event)
    21 {
    22     if (!m_alreadySaveRange)            //执行手势事件之前先保存原始位置
    23     {
    24         this->saveAxisRange();
    25         m_alreadySaveRange = true;
    26     }
    27 
    28     if (QGesture *pinch = event->gesture(Qt::PinchGesture))         //如果是捏合手势,进行缩放处理
    29     {
    30         pinchTriggered(static_cast<QPinchGesture *>(pinch));
    31         event->accept();
    32     }
    33     return true;
    34 }
    35 
    36 //处理缩放事件
    37 void ChartView::pinchTriggered(QPinchGesture *gesture)
    38 {
    39     QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
    40     if (changeFlags & QPinchGesture::ScaleFactorChanged)
    41     {
    42         currentStepScaleFactor = gesture->scaleFactor();            //合计放大系数
    43     }
    44     if (gesture->state() == Qt::GestureFinished)
    45     {
    46         scaleFactor = 1;
    47         scaleFactor *= currentStepScaleFactor;
    48         currentStepScaleFactor = 1;
    49     }
    50 
    51     if(scaleFactor >= 1)
    52     {
    53         this->chart()->zoom(1.05);
    54     }
    55     else if(scaleFactor < 1)
    56     {
    57         this->chart()->zoom(0.95);
    58     }
    59     update();

    .h文件

     1 #pragma once
     2 
     3 #include <QChartView>
     4 #include <QMouseEvent>
     5 #include <QGraphicsSimpleTextItem>
     6 
     7 QT_CHARTS_USE_NAMESPACE
     8 
     9 class ChartView : public QChartView
    10 {
    11     Q_OBJECT
    12 
    13 public:
    14     ChartView(QChart *chart, QWidget *parent = nullptr);
    15     ~ChartView();
    16     // 保存坐标区域,用于复位
    17     void saveAxisRange();
    18 
    19 protected:
    20     void mousePressEvent(QMouseEvent *event);
    21     void mouseMoveEvent(QMouseEvent *event);
    22     void mouseReleaseEvent(QMouseEvent *event);
    23     void wheelEvent(QWheelEvent *event);
    24     void keyPressEvent(QKeyEvent *event);
    25     void keyReleaseEvent(QKeyEvent *event);
    26 
    27 //以下3个为Qt Android下Qchart的缩放(单指触点时默认为鼠标点击,所以移动功能可正常使用)
    28     bool event(QEvent *event) override;             //使用手势实现缩放
    29     bool gestureEvent(QGestureEvent *event);
    30     void pinchTriggered(QPinchGesture *gesture);
    31 
    32 private:
    33     QPoint m_lastPoint;
    34     bool m_isPress;
    35     bool m_ctrlPress;
    36     bool m_alreadySaveRange;
    37     double m_xMin, m_xMax, m_yMin, m_yMax;
    38     QGraphicsSimpleTextItem* m_coordItem;
    39 };

    main文件

     1 #include <QApplication>
     2 #include <QMainWindow>
     3 #include <QLineSeries>
     4 #include "ChartView.h"
     5 
     6 int main(int argc, char *argv[])
     7 {
     8     QApplication a(argc, argv);
     9 
    10     QLineSeries *series = new QLineSeries();
    11 
    12 
    13     series->append(0, 6);
    14     series->append(2, 4);
    15     series->append(3, 8);
    16     series->append(7, 4);
    17     series->append(10, 5);
    18     *series << QPointF(11, 1) << QPointF(13, 3) << QPointF(17, 6) << QPointF(18, 3) << QPointF(20, 2);
    19 
    20     QChart *chart = new QChart();
    21     chart->legend()->hide();
    22     chart->addSeries(series);
    23     chart->createDefaultAxes();
    24     chart->setTitle("图形移动和缩放");
    25 
    26     auto *chartView = new ChartView(chart);//使用自定义ChartView
    27     chartView->setRenderHint(QPainter::Antialiasing);
    28 
    29     QMainWindow window;
    30     window.setCentralWidget(chartView);
    31     window.resize(400, 300);
    32     window.show();
    33 
    34     return a.exec();
    35 }

    .pro文件

     1 QT       += core gui charts
     2 
     3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
     4 
     5 CONFIG += c++11
     6 
     7 # The following define makes your compiler emit warnings if you use
     8 # any Qt feature that has been marked deprecated (the exact warnings
     9 # depend on your compiler). Please consult the documentation of the
    10 # deprecated API in order to know how to port your code away from it.
    11 DEFINES += QT_DEPRECATED_WARNINGS
    12 
    13 # You can also make your code fail to compile if it uses deprecated APIs.
    14 # In order to do so, uncomment the following line.
    15 # You can also select to disable deprecated APIs only up to a certain version of Qt.
    16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    17 
    18 SOURCES += 
    19     ChartView.cpp 
    20     main.cpp
    21 
    22 HEADERS += 
    23     ChartView.h
    24 
    25 FORMS +=
    26 
    27 # Default rules for deployment.
    28 qnx: target.path = /tmp/$${TARGET}/bin
    29 else: unix:!android: target.path = /opt/$${TARGET}/bin
    30 !isEmpty(target.path): INSTALLS += target

    ps:将文件都放在这,下次要用可以直接来复制,方便点。

  • 相关阅读:
    【Luogu】P1419寻找段落(单调队列)
    【Luogu】P1411树(树形高精DP)
    【Luogu】P2886牛继电器(矩阵加速floyd)
    【Luogu】P2657windy数(数位DP)
    【Luogu】P3521ROT-Tree Rotations(线段树合并)
    24-Perl 数据库连接
    23-Perl 面向对象
    22-Perl Socket 编程
    21-Perl 发送邮件
    20-Perl 正则表达式
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13936745.html
Copyright © 2011-2022 走看看