互動式 QGraphicsView(平移/縮放/旋轉)
阿新 • • 發佈:2019-02-04
簡述
Graphics View提供了一個平臺,用於大量自定義 2D 圖元的管理與互動,框架包括一個事件傳播架構,支援場景 Scene 中的圖元 Item 進行精確的雙精度互動功能。Item 可以處理鍵盤事件、滑鼠按下、移動、釋放和雙擊事件,同時也能跟蹤滑鼠移動。
和 Google 地圖一樣,在管理大量 Item 的時候,通常需要 View 具有互動(平移/縮放/旋轉)功能。
|
互動式 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_OBJECT
public :
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.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);
}
這裡,主要重寫了鍵盤及滑鼠事件,具體說明請參考註釋!