交互式QGraphicsView(平移/缩放/旋转)

来源:互联网 发布:剑三藏剑叶英脸型数据 编辑:程序博客网 时间:2024/06/08 15:01

Graphics View提供了一个平台,用于大量自定义 2D 图元的管理与交互,框架包括一个事件传播架构,支持场景 Scene 中的图元 Item 进行精确的双精度交互功能。Item 可以处理键盘事件、鼠标按下、移动、释放和双击事件,同时也能跟踪鼠标移动。

和 Google 地图一样,在管理大量 Item 的时候,通常需要 View 具有交互(平移/缩放/旋转)功能。

  • 简述
  • 交互式 QGraphicsView
    • 效果
    • 源码

交互式 QGraphicsView

便于以后复用,实现一个交互式 QGraphicsView - InteractiveView。

主要功能包括:

  • 平移: 
    • 方式一:鼠标左键按下,然后移动
    • 方式二:按下上/下/左/右键分别向各个方向移动
  • 缩放: 
    • 方式一:鼠标滚轮向上滚动放大,向下滚动缩小
    • 方式二:按加号键(带 Shift)进行放大,按减号键缩小
  • 旋转:按空格键逆时针旋转,回车键顺时针旋转

效果

这里写图片描述

源码

interactive_view.h

#ifndef INTERACTIVE_VIEW_H#define INTERACTIVE_VIEW_H#include <QGraphicsView>class QWheelEvent;class QKeyEvent;class InteractiveView : public QGraphicsView{    Q_OBJECTpublic:    explicit InteractiveView(QWidget *parent = 0);    // 平移速度    void setTranslateSpeed(qreal speed);    qreal translateSpeed() const;    // 缩放的增量    void setZoomDelta(qreal delta);    qreal zoomDelta() const;protected:    // 上/下/左/右键向各个方向移动、加/减键进行缩放、空格/回车键旋转    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;    // 放大/缩小    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;public Q_SLOTS:    void zoomIn();  // 放大    void zoomOut();  // 缩小    void zoom(float scaleFactor); // 缩放 - scaleFactor:缩放的比例因子    void translate(QPointF delta);  // 平移private:    Qt::MouseButton m_translateButton;  // 平移按钮    qreal m_translateSpeed;  // 平移速度    qreal m_zoomDelta;  // 缩放的增量    bool m_bMouseTranslate;  // 平移标识    QPoint m_lastMousePos;  // 鼠标最后按下的位置    qreal m_scale;  // 缩放值};#endif // INTERACTIVE_VIEW_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

平移速度默认为 1.0,可以使用 setTranslateSpeed() 来改变。缩放的增量大小也可以使用 setZoomDelta() 改变。

interactive_view.cpp

#include <QWheelEvent>#include <QKeyEvent>#include "interactive_view.h"#define VIEW_CENTER viewport()->rect().center()#define VIEW_WIDTH  viewport()->rect().width()#define VIEW_HEIGHT viewport()->rect().height()InteractiveView::InteractiveView(QWidget *parent)    : QGraphicsView(parent),      m_translateButton(Qt::LeftButton),      m_scale(1.0),      m_zoomDelta(0.1),      m_translateSpeed(1.0),      m_bMouseTranslate(false){    // 去掉滚动条    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);    setCursor(Qt::PointingHandCursor);    setRenderHint(QPainter::Antialiasing);    setSceneRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX);    centerOn(0, 0);}// 平移速度void InteractiveView::setTranslateSpeed(qreal speed){    // 建议速度范围    Q_ASSERT_X(speed >= 0.0 && speed <= 2.0,               "InteractiveView::setTranslateSpeed", "Speed should be in range [0.0, 2.0].");    m_translateSpeed = speed;}qreal InteractiveView::translateSpeed() const{    return m_translateSpeed;}// 缩放的增量void InteractiveView::setZoomDelta(qreal delta){    // 建议增量范围    Q_ASSERT_X(delta >= 0.0 && delta <= 1.0,               "InteractiveView::setZoomDelta", "Delta should be in range [0.0, 1.0].");    m_zoomDelta = delta;}qreal InteractiveView::zoomDelta() const{    return m_zoomDelta;}// 上/下/左/右键向各个方向移动、加/减键进行缩放、空格/回车键旋转void InteractiveView::keyPressEvent(QKeyEvent *event){    switch (event->key()) {    case Qt::Key_Up:        translate(QPointF(0, -2));  // 上移        break;    case Qt::Key_Down:        translate(QPointF(0, 2));  // 下移        break;    case Qt::Key_Left:        translate(QPointF(-2, 0));  // 左移        break;    case Qt::Key_Right:        translate(QPointF(2, 0));  // 右移        break;    case Qt::Key_Plus:  // 放大        zoomIn();        break;    case Qt::Key_Minus:  // 缩小        zoomOut();        break;    case Qt::Key_Space:  // 逆时针旋转        rotate(-5);        break;    case Qt::Key_Enter:  // 顺时针旋转    case Qt::Key_Return:        rotate(5);        break;    default:        QGraphicsView::keyPressEvent(event);    }}// 平移void InteractiveView::mouseMoveEvent(QMouseEvent *event){    if (m_bMouseTranslate){        QPointF mouseDelta = mapToScene(event->pos()) - mapToScene(m_lastMousePos);        translate(mouseDelta);    }    m_lastMousePos = event->pos();    QGraphicsView::mouseMoveEvent(event);}void InteractiveView::mousePressEvent(QMouseEvent *event){    if (event->button() == m_translateButton) {        // 当光标底下没有 item 时,才能移动        QPointF point = mapToScene(event->pos());        if (scene()->itemAt(point, transform()) == NULL)  {            m_bMouseTranslate = true;            m_lastMousePos = event->pos();        }    }    QGraphicsView::mousePressEvent(event);}void InteractiveView::mouseReleaseEvent(QMouseEvent *event){    if (event->button() == m_translateButton)        m_bMouseTranslate = false;    QGraphicsView::mouseReleaseEvent(event);}// 放大/缩小void InteractiveView::wheelEvent(QWheelEvent *event){    // 滚轮的滚动量    QPoint scrollAmount = event->angleDelta();    // 正值表示滚轮远离使用者(放大),负值表示朝向使用者(缩小)    scrollAmount.y() > 0 ? zoomIn() : zoomOut();}// 放大void InteractiveView::zoomIn(){    zoom(1 + m_zoomDelta);}// 缩小void InteractiveView::zoomOut(){    zoom(1 - m_zoomDelta);}// 缩放 - scaleFactor:缩放的比例因子void InteractiveView::zoom(float scaleFactor){    // 防止过小或过大    qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();    if (factor < 0.07 || factor > 100)        return;    scale(scaleFactor, scaleFactor);    m_scale *= scaleFactor;}// 平移void InteractiveView::translate(QPointF delta){    // 根据当前 zoom 缩放平移数    delta *= m_scale;    delta *= m_translateSpeed;    // view 根据鼠标下的点作为锚点来定位 scene    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);    QPoint newCenter(VIEW_WIDTH / 2 - delta.x(),  VIEW_HEIGHT / 2 - delta.y());    centerOn(mapToScene(newCenter));    // scene 在 view 的中心点作为锚点    setTransformationAnchor(QGraphicsView::AnchorViewCenter);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171

这里,主要重写了键盘及鼠标事件,具体说明请参考注释!



http://blog.csdn.net/liang19890820/article/details/53543017