Qt QChart customizes qChartView (rewrites mouse events) to achieve perfect zooming and panning (new gesture zooming implementation under android)

Function

Implement QtCharts graph movement and zooming:

  1. Hold down the left mouse button and drag the curve to move the curve;
  2. Scroll the mouse wheel to zoom in the X-axis direction of the graph;
  3. Press and hold Ctrl, and roll the mouse wheel to zoom in the Y-axis direction of the graph;
  4. Press the right mouse button to restore the initial state of the graph;
  5. The zooming process takes the current position of the mouse as the zooming center;
  6. The current coordinates will be displayed in the upper left corner during the mouse movement.

accomplish

Inherit QChartView, mainly reimplement mouse events and keyboard events.

  1. Move graphics using the scroll function of QChart;
    void scroll(qreal dx, qreal dy, const QRectF &rect = QRectF());
    when the mouse is pressed, record the pressed state, and record the current coordinate position, and calculate the mouse movement in the movement event Distance, in order to set the distance of graphics scrolling, you can move
  2. Zooming sets the display range of the current coordinate axis;
    void setRange(const QVariant &min, const QVariant &max);

the code

.cpp file

achieve mobile

CSDN QT technology stack outline: Qt development necessary technology stack learning route and materials

 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 }

achieve scaling

 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 }

The following is the zooming of Qchart using gestures under Qt Android

To use gestures, first register in the constructor to allow gestures

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 file

 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 file

 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 file

 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: Put all the files here, you can copy them directly next time you need to use them, which is more convenient.

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project combat, QT embedded development, Quick module, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/m0_73443478/article/details/128118104