New mechanizm zooming QGraphicsView using mouse wheel.

--HG--
branch : develop
This commit is contained in:
dismine 2014-08-19 15:46:52 +03:00
parent 4e1742ded5
commit 35b3c654c6
2 changed files with 152 additions and 74 deletions

View File

@ -34,100 +34,63 @@
#include <QScrollBar>
#include "../tools/vabstracttool.h"
#include <QMouseEvent>
#include <qmath.h>
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief VMainGraphicsView constructor.
* @param parent parent object.
*/
VMainGraphicsView::VMainGraphicsView(QWidget *parent)
:QGraphicsView(parent), _numScheduledScalings(0)
GraphicsViewZoom::GraphicsViewZoom(QGraphicsView* view)
: QObject(view), _view(view), _numScheduledScalings(0)
{
this->setResizeAnchor(QGraphicsView::AnchorUnderMouse);
this->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
this->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
this->setInteractive(true);
_view->viewport()->installEventFilter(this);
_view->setMouseTracking(true);
_modifiers = Qt::ControlModifier;
_zoom_factor_base = 1.0015;
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief wheelEvent handle wheel events.
* @param event wheel event.
*/
//cppcheck-suppress unusedFunction
void VMainGraphicsView::wheelEvent(QWheelEvent *event)
void GraphicsViewZoom::gentle_zoom(double factor)
{
int numSteps = event->delta() / 8 / 15; // see QWheelEvent documentation
_numScheduledScalings += numSteps;
if (_numScheduledScalings * numSteps < 0)
{ // if user moved the wheel in another direction, we reset
_numScheduledScalings = numSteps; // previously scheduled scalings
}
QTimeLine *anim = new QTimeLine(300, this);
anim->setUpdateInterval(20);
if (QApplication::keyboardModifiers() == Qt::ControlModifier)
{// If you press CTRL this code will be executed
connect(anim, &QTimeLine::valueChanged, this, &VMainGraphicsView::scalingTime);
}
else
{
connect(anim, &QTimeLine::valueChanged, this, &VMainGraphicsView::scrollingTime);
}
connect(anim, &QTimeLine::finished, this, &VMainGraphicsView::animFinished);
anim->start();
_view->scale(factor, factor);
_view->centerOn(target_scene_pos);
QPointF delta_viewport_pos = target_viewport_pos - QPointF(_view->viewport()->width() / 2.0,
_view->viewport()->height() / 2.0);
QPointF viewport_center = _view->mapFromScene(target_scene_pos) - delta_viewport_pos;
_view->centerOn(_view->mapToScene(viewport_center.toPoint()));
emit zoomed();
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief scalingTime call each time when need handle scaling.
* @param x value from 0.0 to 1.0
*/
void VMainGraphicsView::scalingTime(qreal x)
void GraphicsViewZoom::set_modifiers(Qt::KeyboardModifiers modifiers)
{
Q_UNUSED(x);
const QPointF p0scene = mapToScene(mapFromGlobal(QCursor::pos()));
_modifiers = modifiers;
qreal factor = 1.0 + static_cast<qreal>(_numScheduledScalings) / 50.0;
scale(factor, factor);
const QPointF p1mouse = mapFromScene(p0scene);
const QPointF move = p1mouse - this->mapFromGlobal(QCursor::pos()); // The move
horizontalScrollBar()->setValue(static_cast<qint32>(move.x()) + horizontalScrollBar()->value());
verticalScrollBar()->setValue(static_cast<qint32>(move.y()) + verticalScrollBar()->value());
VAbstractTool::NewSceneRect(this->scene(), this);
emit NewFactor(factor);
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief scrollingTime call each time when need handle scrolling.
* @param x value from 0.0 to 1.0
*/
void VMainGraphicsView::scrollingTime(qreal x)
void GraphicsViewZoom::set_zoom_factor_base(double value)
{
_zoom_factor_base = value;
}
//---------------------------------------------------------------------------------------------------------------------
void GraphicsViewZoom::scrollingTime(qreal x)
{
Q_UNUSED(x);
qreal factor = 1.0;
if (_numScheduledScalings < 0)
{
verticalScrollBar()->setValue(qRound(verticalScrollBar()->value() + factor*3.5));
emit NewFactor(factor);
factor = factor*2.8;
}
else
{
verticalScrollBar()->setValue(qRound(verticalScrollBar()->value() - factor*3.5));
emit NewFactor(factor);
factor = factor*-2.8;
}
_view->verticalScrollBar()->setValue(qRound(_view->verticalScrollBar()->value() + factor));
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief animFinished
*/
void VMainGraphicsView::animFinished()
void GraphicsViewZoom::animFinished()
{
if (_numScheduledScalings > 0)
{
@ -140,6 +103,69 @@ void VMainGraphicsView::animFinished()
sender()->~QObject();
}
//---------------------------------------------------------------------------------------------------------------------
bool GraphicsViewZoom::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::MouseMove)
{
QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
QPointF delta = target_viewport_pos - mouse_event->pos();
if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5)
{
target_viewport_pos = mouse_event->pos();
target_scene_pos = _view->mapToScene(mouse_event->pos());
}
}
else if (event->type() == QEvent::Wheel)
{
QWheelEvent* wheel_event = static_cast<QWheelEvent*>(event);
if (QApplication::keyboardModifiers() == _modifiers)
{
if (wheel_event->orientation() == Qt::Vertical)
{
double angle = wheel_event->angleDelta().y();
double factor = qPow(_zoom_factor_base, angle);
gentle_zoom(factor);
return true;
}
}
else
{
int numSteps = wheel_event->delta() / 8 / 15; // see QWheelEvent documentation
_numScheduledScalings += numSteps;
if (_numScheduledScalings * numSteps < 0)
{ // if user moved the wheel in another direction, we reset
_numScheduledScalings = numSteps; // previously scheduled scalings
}
QTimeLine *anim = new QTimeLine(300, this);
anim->setUpdateInterval(20);
connect(anim, &QTimeLine::valueChanged, this, &GraphicsViewZoom::scrollingTime);
connect(anim, &QTimeLine::finished, this, &GraphicsViewZoom::animFinished);
anim->start();
return true;
}
}
Q_UNUSED(object)
return false;
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief VMainGraphicsView constructor.
* @param parent parent object.
*/
VMainGraphicsView::VMainGraphicsView(QWidget *parent)
:QGraphicsView(parent), zoom(nullptr)
{
zoom = new GraphicsViewZoom(this);
this->setResizeAnchor(QGraphicsView::AnchorUnderMouse);
this->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
this->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
this->setInteractive(true);
}
//---------------------------------------------------------------------------------------------------------------------
void VMainGraphicsView::ZoomIn()
{

View File

@ -29,8 +29,65 @@
#ifndef VMAINGRAPHICSVIEW_H
#define VMAINGRAPHICSVIEW_H
#include <QObject>
#include <QGraphicsView>
/*!
* This class adds ability to zoom QGraphicsView using mouse wheel. The point under cursor
* remains motionless while it's possible.
*
* Note that it becomes not possible when the scene's
* size is not large enough comparing to the viewport size. QGraphicsView centers the picture
* when it's smaller than the view. And QGraphicsView's scrolls boundaries don't allow to
* put any picture point at any viewport position.
*
* When the user starts scrolling, this class remembers original scene position and
* keeps it until scrolling is completed. It's better than getting original scene position at
* each scrolling step because that approach leads to position errors due to before-mentioned
* positioning restrictions.
*
* When zommed using scroll, this class emits zoomed() signal.
*
* Usage:
*
* new Graphics_view_zoom(view);
*
* The object will be deleted automatically when the view is deleted.
*
* You can set keyboard modifiers used for zooming using set_modified(). Zooming will be
* performed only on exact match of modifiers combination. The default modifier is Ctrl.
*
* You can change zoom velocity by calling set_zoom_factor_base().
* Zoom coefficient is calculated as zoom_factor_base^angle_delta
* (see QWheelEvent::angleDelta).
* The default zoom factor base is 1.0015.
*/
class GraphicsViewZoom : public QObject
{
Q_OBJECT
public:
GraphicsViewZoom(QGraphicsView* view);
void gentle_zoom(double factor);
void set_modifiers(Qt::KeyboardModifiers modifiers);
void set_zoom_factor_base(double value);
signals:
void zoomed();
public slots:
void scrollingTime(qreal x);
void animFinished();
private:
QGraphicsView* _view;
Qt::KeyboardModifiers _modifiers;
double _zoom_factor_base;
QPointF target_scene_pos;
QPointF target_viewport_pos;
bool eventFilter(QObject* object, QEvent* event);
private:
/** @brief _numScheduledScalings keep number scheduled scalings. */
qint32 _numScheduledScalings;
};
/**
* @brief The VMainGraphicsView class main scene view.
*/
@ -53,20 +110,15 @@ signals:
*/
void MouseRelease();
public slots:
void scalingTime(qreal x);
void scrollingTime(qreal x);
void animFinished();
void ZoomIn();
void ZoomOut();
void ZoomOriginal();
void ZoomFitBest();
protected:
void wheelEvent ( QWheelEvent * event );
void mousePressEvent(QMouseEvent *mousePress);
void mouseReleaseEvent(QMouseEvent *event);
private:
/** @brief _numScheduledScalings keep number scheduled scalings. */
qint32 _numScheduledScalings;
GraphicsViewZoom* zoom;
};
#endif // VMAINGRAPHICSVIEW_H