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

Qt 专栏收录该内容
118 篇文章 25 订阅

由于项目要求,需要在QWidget中实现一个手势操作的功能,对图片进行放大/缩小/平移功能,并且还需要支持通过鼠标和键盘来实现该功能。其实这种功能在QGraphicsView中实现比较简单, 不过在QWidget中也能实现,本次通过QGestureEvent来捕捉手势操作,然后对图片进行缩放或者移动。

废话不多说,直接上代码


首先来看头文件:

class QGestureEvent;
class QPanGesture;
class QPinchGesture;
class QSwipeGesture;
class CProjectionPicture;

class CProjectionPicture : public QWidget
{
    Q_OBJECT
public:
    CProjectionPicture(QWidget *parent = 0);

    void setPicture(QImage & image);

protected:
    // 放大/缩小
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
    void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;


    void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
    // 平移
    void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;

    bool event(QEvent *event) Q_DECL_OVERRIDE;
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
    void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;


public Q_SLOTS:
    void zoomIn();  // 放大
    void zoomOut();  // 缩小
    void zoom(float scale); // 缩放 - scaleFactor:缩放的比例因子
    void translate(QPointF delta);  // 平移


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

    QImage loadImage(const QString &fileName);

    QImage currentImage;

    qreal horizontalOffset;
    qreal verticalOffset;

    qreal scaleFactor;
    qreal currentStepScaleFactor;
    Qt::MouseButton m_translateButton;  // 平移按钮
    bool m_bMouseTranslate;
    qreal m_zoomDelta;  // 缩放的增量
    QPoint m_lastMousePos;  // 鼠标最后按下的位置


};

源文件:

CProjectionPicture::CProjectionPicture(QWidget *parent)
    : QWidget(parent),
    horizontalOffset(0),
    verticalOffset(0),
    scaleFactor(1),
    currentStepScaleFactor(1),
    m_translateButton(Qt::LeftButton),
    m_bMouseTranslate(false),
    m_zoomDelta(0.2),
{
    this->setFocusPolicy(Qt::ClickFocus);
 
    grabGesture(Qt::PanGesture);
    grabGesture(Qt::PinchGesture);
    grabGesture(Qt::SwipeGesture);
}
void CProjectionPicture::setPicture(QImage &image)
{
    currentImage = image.convertToFormat(QImage::Format_RGB888);
    update();
}


bool CProjectionPicture::event(QEvent *event)
{
    if (event->type() == QEvent::Gesture)
        return gestureEvent(static_cast<QGestureEvent*>(event));
    return QWidget::event(event);
}

void CProjectionPicture::paintEvent(QPaintEvent*)
{
    QPainter painter(this);
    QImage image = currentImage;

   
    if(!image.isNull()){
        image = image.scaled(this->width()*currentStepScaleFactor * scaleFactor,
                             this->height()*currentStepScaleFactor * scaleFactor,
                             Qt::KeepAspectRatio,
                             Qt::SmoothTransformation);
    }
        
    const qreal iw = image.width();
    const qreal ih = image.height();
    const qreal wh = height();
    const qreal ww = width();

    painter.translate(ww/2, wh/2);
    painter.translate(horizontalOffset, verticalOffset);
    //painter.scale(currentStepScaleFactor * scaleFactor, currentStepScaleFactor * scaleFactor);
    painter.translate(-iw/2, -ih/2);
    painter.drawImage(0,0,image);

}

void CProjectionPicture::mouseDoubleClickEvent(QMouseEvent *)
{
    scaleFactor = 1;
    currentStepScaleFactor = 1;
    verticalOffset = 0;
    horizontalOffset = 0;
    update();
}

bool CProjectionPicture::gestureEvent(QGestureEvent *event)
{
    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 CProjectionPicture::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();
    horizontalOffset += delta.x();
    verticalOffset += delta.y();
    update();
}

void CProjectionPicture::pinchTriggered(QPinchGesture *gesture)
{
    QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
    if (changeFlags & QPinchGesture::ScaleFactorChanged) {
        currentStepScaleFactor = gesture->totalScaleFactor();
    }
    if (gesture->state() == Qt::GestureFinished) {
        scaleFactor *= currentStepScaleFactor;
        currentStepScaleFactor = 1;
    }
    update();
}

void CProjectionPicture::resizeEvent(QResizeEvent*e)
{
    update();
    QWidget::resizeEvent(e);
}

// 上/下/左/右键向各个方向移动、加/减键进行缩放
void CProjectionPicture::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    qDebug() << event->key();
    case Qt::Key_Up:
        translate(QPointF(0, -5));  // 上移
        break;
    case Qt::Key_Down:
        translate(QPointF(0, 5));  // 下移
        break;
    case Qt::Key_Left:
        translate(QPointF(-5, 0));  // 左移
        break;
    case Qt::Key_Right:
        translate(QPointF(5, 0));  // 右移
        break;
    case Qt::Key_Plus:  // 放大
        zoomIn();
        break;
    case Qt::Key_Minus:  // 缩小
        zoomOut();
        break;
    default:
        QWidget::keyPressEvent(event);
    }
    QWidget::keyPressEvent(event);
}

// 平移
void CProjectionPicture::mouseMoveEvent(QMouseEvent *event)
{
    if (m_bMouseTranslate){
        QPointF mouseDelta = event->pos() - m_lastMousePos;
        translate(mouseDelta);
    }

    m_lastMousePos = event->pos();

    QWidget::mouseMoveEvent(event);
}

void CProjectionPicture::mousePressEvent(QMouseEvent *event)
{
    qDebug() << "CProjectionPicture::mousePressEvent";
    if (event->button() == m_translateButton) {
        m_bMouseTranslate = true;
        m_lastMousePos = event->pos();
        setCursor(Qt::OpenHandCursor);
    }

    QWidget::mousePressEvent(event);
}

void CProjectionPicture::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == m_translateButton)
    {
        m_bMouseTranslate = false;
        setCursor(Qt::ArrowCursor);
    }

    QWidget::mouseReleaseEvent(event);
}

// 放大/缩小
void CProjectionPicture::wheelEvent(QWheelEvent *event)
{
    qDebug() << "CProjectionPicture::wheelEvent";
//    QPoint numPixels = event->pixelDelta();
    QPoint scrallAmount = event->angleDelta();
    if(scrallAmount.y() > 0){
        zoomIn();
    }
    else if(scrallAmount.y() < 0){
        zoomOut();
    }
    QWidget::wheelEvent(event);
}

// 放大
void CProjectionPicture::zoomIn()
{
    zoom(1 + m_zoomDelta);
}

// 缩小
void CProjectionPicture::zoomOut()
{
    zoom(1 - m_zoomDelta);
}

// 缩放 - scaleFactor:缩放的比例因子
void CProjectionPicture::zoom(float scale)
{
    scaleFactor *= scale;
    update();
}

// 平移
void CProjectionPicture::translate(QPointF delta)
{
    horizontalOffset += delta.x();
    verticalOffset += delta.y();
    update();
}

本文参考:http://blog.csdn.net/liang19890820/article/details/53543017

  • 4
    点赞
  • 10
    评论
  • 33
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值