欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt for android下通过手势事件对Chart曲线图缩放和平移的实现

程序员文章站 2022-07-14 09:02:06
...

一、功能要求

  对Qt5.14开发的手机APP中绘制的曲线,进行触摸操作,实现对曲线的缩放和坐标轴平移,还需实现缩放和平移后的坐标复原。

二、实现过程

实现过程总体比较曲折,具体如下:

第一次:参考例子程序zoomlinechart,采用event,gestureEvent以及mousePressEvent、mouseMoveEvent、mouseReleaseEvent实现,但是发现存在两个问题:

1)只识别到PinchGesture,通过“捏”动作实现Chart图缩放,但是不能检测到panGesture,无法按照例程中的实现Chart图平移

2)在ChartView内点击,只检测到mousePressEvent,无法检测到mouseMoveEvent、mouseReleaseEvent,即无法在Chart图上拖动实现平移,但是只能在ChartView外窗口的区域才能实现Chart图平移,在Chart图上双击可以坐标复原。

第二次:又通过setAcceptTouchEvent设置接收触摸事件,但是发现窗口内Chart图下面的保存按钮和画面关闭按钮不起作用了;

第三次:通过网上查找资料了解到,在Android或linux下,存在无法检测到单指移动的panGetureEvent事件,而不像在例程说明中的是基于windows系统的情况,*网站https://*.com/questions/49287314/qgestureevent-for-mouse

的介绍,通过手势识别器panGestureRecognizer()来识别panGesture,将网站的程序复制到项目中,编译后出现运行崩溃的问题,注释掉panGestureRecognizer::create(Object *target)函数,再没有出现程序崩溃的情况,但是触摸后没有任何反应,程序中的qDebug()也没有显示出检测到panGesture程序的执行。

最后:通过网上查找资料了解到,QGraphicsView的对象有mouseEvent事件,再次对例子程序zoomlinechart阅读发现,程序中单独新建了一个ChartView类,而没用系统的QchartView类,在Chartview下的protected内建有mousePressEvent,mouseMoveEvent,mouseMoveEvent等事件,事件函数内最后一句:return QChartView::mouseMoveEvent(event);也表明了不同于我第一次在程序中将此句只能写成的:return QWidget::mouseMoveEvent(event);,也就解释了为什么在ChartView内mouseMoveEvent和mouseReleaseEvent动作检测不到,而只能在ChartView外窗口的区域检测到的原因。

三、程序

.h文件程序:

#ifndef PITCHTRAJECTORY_H
#define PITCHTRAJECTORY_H

#include <QWidget>
#include <QToolButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QFormLayout>
#include <QGridLayout>
#include <QFileDialog>
#include <QStandardPaths>
#include <QAbstractItemView>
#include <QtCharts/QChart>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>    //用于创建折线图
#include <QtCharts/QSplineSeries>  //用于创建曲线图
#include <QtCharts/QValueAxis>   //创建坐标轴
#include <QtCharts/QCategoryAxis>
#include <QSvgGenerator>
#include <QtWidgets/QGesture>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QGraphicsView>
#include <QPointF>


QT_BEGIN_NAMESPACE
class QGestureEvent;
class ChartView;
QT_END_NAMESPACE


QT_CHARTS_USE_NAMESPACE
class pitchtrajectoryshow : public QWidget
{
    Q_OBJECT

public:
  explicit  pitchtrajectoryshow(QWidget *parent = nullptr);
    ~pitchtrajectoryshow();

    QValueAxis *axisX1;
    QValueAxis *axisY1;
    QChart *chart1;
    QSplineSeries *series_deepopenholepitch;
    QSplineSeries *series_deeppitch;
  // QChartView  *chartview1;
    ChartView *chartview1;
    QString charfileName1;


private:
   QToolButton *closechartsBtn;
   QToolButton *savechartsBtn;
   QHBoxLayout *pitchtrajectoryshowLayout1;
   QVBoxLayout *pitchtrajectoryshowLayout;


   qreal scaleFactor=1;
   qreal currentStepScaleFactor=1;
   /* qreal horizontalOffset=0;
   qreal verticalOffset=0;
   Qt::MouseButton m_translateButton=Qt::LeftButton;  // 平移按钮
   bool m_bMouseTranslate=false;
   qreal m_zoomDelta=0.2;  // 缩放的增量
   QPoint m_lastMousePos;  // 鼠标最后按下的位置*/


   bool gestureEvent(QGestureEvent *event);
   void pinchTriggered(QPinchGesture*);
   void panTriggered(QPanGesture*);


protected:
     void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
     bool event(QEvent *event) Q_DECL_OVERRIDE;

public slots:
   void deeppitchcharts_Recv(QString fileName,QSplineSeries *series0_0,QSplineSeries *series1);
   void deltadata_Recv(qreal horizontalOffset,qreal verticalOffset);

protected slots:
    void closechartsBtn_clicked();
    void savechartsBtn_clicked();

signals:
   void closepitchchartssignal_Send(void);


};

//新建ChartView类

class ChartView : public QChartView
{
     Q_OBJECT
public:
    ChartView(QChart *chart, QWidget *parent = 0);

    Qt::MouseButton m_translateButton=Qt::LeftButton;  // 平移按钮
    bool m_bMouseTranslate=false;
    QPoint m_lastMousePos;  // 鼠标最后按下的位置
    qreal horizontalOffset=0;
    qreal verticalOffset=0;
protected:

    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

signals:
      void deltadata_Send(qreal horizontalOffset,qreal verticalOffset);

};

#endif // PITCHTRAJECTORY_H
.cpp文件:
bool pitchtrajectoryshow::event(QEvent *event)
{
    if (event->type() == QEvent::Gesture)
        return gestureEvent(static_cast<QGestureEvent*>(event));
    return QWidget::event(event);
}

void pitchtrajectoryshow::mouseDoubleClickEvent(QMouseEvent *)
{
    qDebug()<<"识别到鼠标双击动作!";

    //重新复位大小
    chart1->zoomReset();
    chart1->axisX()->setRange(0, 30);
    chart1->axisY()->setRange(-10, 10);
    scaleFactor = 1;
    currentStepScaleFactor = 1;
    chartview1->verticalOffset=0;
    chartview1->horizontalOffset=0;
    chartview1->m_bMouseTranslate=false;
    update();
}

bool pitchtrajectoryshow::gestureEvent(QGestureEvent *event)
{
    qDebug() << "gestureEvent():" << event->gestures().size();
    if (QGesture *pan = event->gesture(Qt::PanGesture))
        panTriggered(static_cast<QPanGesture *>(pan));
    if (QGesture *pinch = event->gesture(Qt::PinchGesture))
        pinchTriggered(static_cast<QPinchGesture *>(pinch));
    return true;
}

void pitchtrajectoryshow::panTriggered(QPanGesture *gesture)
{
   qDebug()<<"识别到手势pan动作!";
 #ifndef QT_NO_CURSOR
    switch (gesture->state())
    {
    case Qt::GestureStarted:
    case Qt::GestureUpdated:
        setCursor(Qt::SizeAllCursor);
        break;
    default:
        setCursor(Qt::ArrowCursor);
    }
#endif
    QPointF delta = gesture->delta();
   chartview1->horizontalOffset += delta.x();
   chartview1->verticalOffset += delta.y();

    //平移
    chart1->scroll(chartview1->horizontalOffset, chartview1->verticalOffset);
    update();
}

void pitchtrajectoryshow::pinchTriggered(QPinchGesture *gesture)
{
    qDebug()<<"识别到手势pinch动作!";
    QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
    if (changeFlags & QPinchGesture::ScaleFactorChanged)
    {
        currentStepScaleFactor = gesture->totalScaleFactor();
    }
    if (gesture->state() == Qt::GestureFinished)
    {
        scaleFactor *= currentStepScaleFactor;
        currentStepScaleFactor = 1;
    }

    //缩放
    chart1->zoom(scaleFactor); //缩放
    update();
}

void pitchtrajectoryshow::deltadata_Recv(qreal horizontalOffset,qreal verticalOffset)
{
     chart1->scroll(horizontalOffset, verticalOffset);
     update();
}




void ChartView::mouseMoveEvent(QMouseEvent *event)
{
      qDebug()<<"识别到鼠标移动动作!";
    if (m_bMouseTranslate)
    {
        QPointF mouseDelta = event->pos() - m_lastMousePos;
        horizontalOffset += mouseDelta.x();
        verticalOffset += mouseDelta.y();
        emit deltadata_Send(horizontalOffset,verticalOffset);
    }
    m_lastMousePos = event->pos();
    QChartView::mouseMoveEvent(event);

}

void ChartView::mousePressEvent(QMouseEvent *event)
{

       qDebug()<<"识别到鼠标压下动作!";
     if (event->button() == m_translateButton)
     {
         m_bMouseTranslate = true;
         m_lastMousePos = event->pos();
         setCursor(Qt::OpenHandCursor);
     }
    // QWidget::mousePressEvent(event);
     QChartView::mousePressEvent(event);
}
void ChartView::mouseReleaseEvent(QMouseEvent *event)
{
      qDebug()<<"识别到鼠标释放动作!";
    if (event->button() == m_translateButton)
    {
        m_bMouseTranslate = false;
        setCursor(Qt::ArrowCursor);
    }
  // QWidget::mouseReleaseEvent(event);
   QChartView::mouseReleaseEvent(event);
}
曲线界面:

Qt for android下通过手势事件对Chart曲线图缩放和平移的实现

四、小结

1、通过pitchtrajectoryshow窗口下PinchGesture动作事件识别,触发函数下: chart1->zoom(scaleFactor),实现图片的缩放;

2、通过ChartView下mousePressEvent、mouseMoveEvent、mouseReleasesEvent动作识别,在函数void pitchtrajectoryshow::deltadata_Recv(qreal horizontalOffset,qreal verticalOffset)  中实现平移量数据的接收,chart1->scroll(horizontalOffset, verticalOffset); 实现chartView内chart曲线的平移

3、通过pitchtrajectoryshow窗口下mouseDoubleClickEvent事件, chart1->zoomReset(); chart1->axisX()->setRange(0, 30);chart1->axisY()->setRange(-10, 10);将chart坐标复原。