Qt for android下通过手势事件对Chart曲线图缩放和平移的实现
一、功能要求
对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);
}
曲线界面:
四、小结
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坐标复原。