Qt实现手势缩放和平移(QGestureEvent)

9 篇文章 0 订阅

        最近项目中遇到一个预览图片的需求,同时能够对手势进行处理,可以处理手势的放大、缩小和平移,其中移动可以通过重写鼠标事件实现。而手势事件之前则没有处理过。查阅资料发现Qt自带了一个手势示例,如下图所示,通过阅读代码发现可以通过QGestureEvent事件实现。具体代码如下。

#pragma once

#include "ui_testGesture.h"

#include <QWidget>
#include <QGesture>
#include <QPanGesture>
#include <QPinchGesture>
#include <QGestureEvent>

class testGesture : public QWidget
{
    Q_OBJECT

public:
    testGesture(QWidget *parent = nullptr);
    ~testGesture();

    /**
     * brief:注册所关注的手势事件.
     * 
     * \param gestures:需要关注的事件
     */
    void grabGestures(const QList<Qt::GestureType>& gestures);

protected:
    /**
     * brief:重写paintevent。这是实现的核心,通过修改绘制的中心坐标实现图像根据手势的移动.
     * 
     * \param event
     */
    void paintEvent(QPaintEvent* event)override;
    /**
     * brief:尺寸变化.
     * 
     * \param event
     */
    void resizeEvent(QResizeEvent* event)override;
    /**
     * brief:双击事件,双击后所有的缩放移动等均失效,恢复到初始状态.
     * 
     * \param event
     */
    void mouseDoubleClickEvent(QMouseEvent* event)override;
    /**
     * brief:按下事件,任务需要移动了,不再处理手势.
     * 
     * \param event
     */
    void mousePressEvent(QMouseEvent* event)override;
    /**
     * brief:按下并移动的处理.
     * 
     * \param event
     */
    void mouseMoveEvent(QMouseEvent* event)override;
    /**
     * brief:.
     * 
     * \param event
     */
    void mouseReleaseEvent(QMouseEvent* event)override;
    /**
     * brief:事件过滤处理.
     * 
     * \param event
     * \return 
     */
    bool event(QEvent* event)override;

private:
    bool gestureEvent(QGestureEvent* event);
    void panTriggered(QPanGesture* gesture);
    void pinchTriggered(QPinchGesture* gesture);
    void swipeTriggered(QSwipeGesture* gesture);

private:
    Ui::testGestureClass ui;
    qreal m_horizontalOffset{ 0 };    //水平方向偏移量
    qreal m_verticalOffset{ 0 };      //垂直方向偏移量
    qreal m_rotationAngle{ 0 };       //旋转角度
    qreal m_scaleFactor{ 1 };         //缩放比例
    qreal m_currentStepScaleFactor{ 1 };   //一次手势之后缩放的比例
    QPoint m_lastPoint{ 0,0 };          //上次点击位置

    bool m_bIsPressed{ false };         //是否有过点击事件
};

这里最核心的处理便是paintevent的重写和pinchTriggered事件的处理函数。在pinchTriggered处理函数中根据手势的类型,将缩放的比例以及旋转的比例记录下来,结束后则计算此次总的比例并记录在成员变量中。而在paintevent中则调用tanslate函数,依照缩放,旋转值重新计算绘图的位置,从而实现了缩放,旋转。至于panTriggered和swipeTriggered事件因需求中不关注,便未做处理,可根据自身需要进行响应的处理。

#include "testGesture.h"

#include <QDebug>
#include <QPainter>

testGesture::testGesture(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	setFixedSize({ 1920,1080 });
	grabGestures({});
}

testGesture::~testGesture()
{}

void testGesture::grabGestures(const QList<Qt::GestureType>&gestures)
{
	QList<Qt::GestureType> gesturess;
	//关注移动,缩放和扫动手势
	gesturess << Qt::PanGesture;
	gesturess << Qt::PinchGesture;
	gesturess << Qt::SwipeGesture;
	foreach(Qt::GestureType gesture, gesturess)
		grabGesture(gesture);
}

void testGesture::paintEvent(QPaintEvent* event)
{
	QPainter p(this);
	QPixmap pix("E:/1.jpg");

	const qreal iw = pix.width();
	const qreal ih = pix.height();
	const qreal wh = height();
	const qreal ww = width();

	//首先将坐标系移动到整个屏幕的中心
	p.translate(ww / 2, wh / 2);
	//然后依据偏移量,再计算出来新的坐标系中心
	//第二次变换是在上次的基础上进行的计算,也就是translate的所有值是累加的
	p.translate(m_horizontalOffset, m_verticalOffset);
	//qDebug() << "qqqq" << m_horizontalOffset << ":" << m_verticalOffset;
	//p.rotate(m_rotationAngle);
	//对坐标系进行一个比例放缩
	p.scale(m_currentStepScaleFactor * m_scaleFactor, m_currentStepScaleFactor * m_scaleFactor);
	//又进行了一个坐标系中心的变化,减去图片的一半一半,也就是到了图片的左上角
	//上边计算了偏移量,所以就是移动之后的图片需要绘制的位置,缩放也相应的在上边进行了设置
	p.translate(-iw / 2, -ih / 2);
	p.drawPixmap(0, 0, pix);
}

void testGesture::resizeEvent(QResizeEvent* event)
{
	update();
}

void testGesture::mouseDoubleClickEvent(QMouseEvent* event)
{
	//双击后将双击偏移量,缩放比例,旋转角度都设置为初始值
	m_rotationAngle = 0;
	m_scaleFactor = 1;
	m_currentStepScaleFactor = 1;
	m_verticalOffset = 0;
	m_horizontalOffset = 0;
	update();
}

void testGesture::mousePressEvent(QMouseEvent* event)
{
	//鼠标按下后不再处理手势,并记录鼠标按下的位置
	m_bIsPressed = true;
	m_lastPoint = event->pos();
}

void testGesture::mouseMoveEvent(QMouseEvent* event)
{
	//如果是处理移动事件
	if (m_bIsPressed)
	{
		//计算偏移量
		QPointF mouseDelta = event->pos() - m_lastPoint;
		m_lastPoint = event->pos();
		m_horizontalOffset += mouseDelta.x();
		m_verticalOffset += mouseDelta.y();
		update();
	}
}

void testGesture::mouseReleaseEvent(QMouseEvent* event)
{
	//不再处理移动
	m_bIsPressed = false;
}

bool testGesture::event(QEvent* event)
{
	//如果是手势,需要给到手势的分派函数
	if (event->type() == QEvent::Gesture)
	{
		return gestureEvent(static_cast<QGestureEvent*>(event));
	}
	return QWidget::event(event);
}

bool testGesture::gestureEvent(QGestureEvent* event)
{
	//给到对应的处理事件
	if (QGesture* swipe = event->gesture(Qt::SwipeGesture))
		swipeTriggered(static_cast<QSwipeGesture*>(swipe));
	else 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 testGesture::panTriggered(QPanGesture* gesture)
{
#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();
	//qDebug() << "panTriggered():" << gesture;
	//m_horizontalOffset += delta.x();
	//m_verticalOffset += delta.y();
	update();
}

void testGesture::pinchTriggered(QPinchGesture* gesture)
{
	QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
	//旋转角度的变化记录
	if (changeFlags & QPinchGesture::RotationAngleChanged) 
	{
		qreal rotationDelta = gesture->rotationAngle() - gesture->lastRotationAngle();
		m_rotationAngle += rotationDelta;
		qDebug() << "pinchTriggered(): rotate by" <<
			rotationDelta << "->" << m_rotationAngle;
	}
	//缩放比例的变化记录
	if (changeFlags & QPinchGesture::ScaleFactorChanged) 
	{
		m_currentStepScaleFactor = gesture->totalScaleFactor();
		qDebug() << "pinchTriggered(): zoom by" <<
			gesture->scaleFactor() << "->" << m_currentStepScaleFactor;
	}
	//手势结束后将锁防值累乘
	if (gesture->state() == Qt::GestureFinished) 
	{
		qDebug() << "finished::" << m_currentStepScaleFactor;
		m_scaleFactor *= m_currentStepScaleFactor;
		m_currentStepScaleFactor = 1;
	}
	update();
}

void testGesture::swipeTriggered(QSwipeGesture* gesture)
{
	if (gesture->state() == Qt::GestureFinished) {
		if (gesture->horizontalDirection() == QSwipeGesture::Left
			|| gesture->verticalDirection() == QSwipeGesture::Up) {
			//qDebug() << "swipeTriggered(): swipe to previous";
			//goPrevImage();
		}
		else {
			//qDebug() << "swipeTriggered(): swipe to next";
			//goNextImage();
		}
		update();
	}
}

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值