QGraphicsView Zooming in and out under mouse position using mouse wheel finally

works like i want.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2015-12-02 20:39:25 +02:00
parent 8506afc056
commit 6cd674ec0f
2 changed files with 50 additions and 13 deletions

View File

@ -55,11 +55,20 @@ GraphicsViewZoom::GraphicsViewZoom(QGraphicsView* view)
void GraphicsViewZoom::gentle_zoom(double factor) void GraphicsViewZoom::gentle_zoom(double factor)
{ {
_view->scale(factor, factor); _view->scale(factor, factor);
if (factor < 1)
{
// Because 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 we will provide fictive scene size.
// Temporary and bigger than view, scene size will help position an image under cursor.
FictiveSceneRect(_view->scene(), _view);
}
_view->centerOn(target_scene_pos); _view->centerOn(target_scene_pos);
QPointF delta_viewport_pos = target_viewport_pos - QPointF(_view->viewport()->width() / 2.0, QPointF delta_viewport_pos = target_viewport_pos - QPointF(_view->viewport()->width() / 2.0,
_view->viewport()->height() / 2.0); _view->viewport()->height() / 2.0);
QPointF viewport_center = _view->mapFromScene(target_scene_pos) - delta_viewport_pos; QPointF viewport_center = _view->mapFromScene(target_scene_pos) - delta_viewport_pos;
_view->centerOn(_view->mapToScene(viewport_center.toPoint())); _view->centerOn(_view->mapToScene(viewport_center.toPoint()));
// In the end we just set correct scene size
VMainGraphicsView::NewSceneRect(_view->scene(), _view);
emit zoomed(); emit zoomed();
} }
@ -112,12 +121,12 @@ void GraphicsViewZoom::animFinished()
* If don't do that we will zoom using old value cursor position on scene. It is not what we expect. * If don't do that we will zoom using old value cursor position on scene. It is not what we expect.
* Almoust the same we do in method GraphicsViewZoom::eventFilter. * Almoust the same we do in method GraphicsViewZoom::eventFilter.
*/ */
QPoint pos = _view->mapFromGlobal(QCursor::pos()); const QPoint pos = _view->mapFromGlobal(QCursor::pos());
QPointF delta = target_scene_pos - _view->mapToScene(pos); const QPointF delta = target_scene_pos - _view->mapToScene(pos);
if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5) if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5)
{ {
target_viewport_pos = pos; target_viewport_pos = pos;
target_scene_pos = _view->mapToScene(pos); target_scene_pos = _view->mapToScene(pos);
} }
} }
@ -173,6 +182,39 @@ bool GraphicsViewZoom::eventFilter(QObject *object, QEvent *event)
return false; return false;
} }
//---------------------------------------------------------------------------------------------------------------------
void GraphicsViewZoom::FictiveSceneRect(QGraphicsScene *sc, QGraphicsView *view)
{
SCASSERT(sc != nullptr);
SCASSERT(view != nullptr);
//Calculate view rect
//to receive the currently visible area, map the widgets bounds to the scene
const QPointF a = view->mapToScene(0, 0 );
const QPointF b = view->mapToScene(view->viewport()->width(), view->viewport()->height());
QRectF viewRect = QRectF( a, b );
//Calculate scene rect
const QRectF sceneRect = sc->sceneRect();
if (not sceneRect.contains(viewRect))
{//Scene less than view
//Scale view
QLineF topLeftRay(viewRect.center(), viewRect.topLeft());
topLeftRay.setLength(topLeftRay.length()*2);
QLineF bottomRightRay(viewRect.center(), viewRect.bottomRight());
bottomRightRay.setLength(bottomRightRay.length()*2);
viewRect = QRectF(topLeftRay.p2(), bottomRightRay.p2());
//Unite two rects
const QRectF newRect = sceneRect.united(viewRect);
sc->setSceneRect(newRect);
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
* @brief VMainGraphicsView constructor. * @brief VMainGraphicsView constructor.

View File

@ -36,11 +36,6 @@
* This class adds ability to zoom QGraphicsView using mouse wheel. The point under cursor * This class adds ability to zoom QGraphicsView using mouse wheel. The point under cursor
* remains motionless while it's possible. * 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 * 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 * 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 * each scrolling step because that approach leads to position errors due to before-mentioned
@ -79,18 +74,18 @@ public slots:
void scrollingTime(qreal x); void scrollingTime(qreal x);
void animFinished(); void animFinished();
private: private:
Q_DISABLE_COPY(GraphicsViewZoom)
QGraphicsView* _view; QGraphicsView* _view;
Qt::KeyboardModifiers _modifiers; Qt::KeyboardModifiers _modifiers;
double _zoom_factor_base; double _zoom_factor_base;
QPointF target_scene_pos; QPointF target_scene_pos;
QPointF target_viewport_pos; QPointF target_viewport_pos;
QTimeLine *anim; QTimeLine *anim;
bool eventFilter(QObject* object, QEvent* event);
private:
Q_DISABLE_COPY(GraphicsViewZoom)
/** @brief _numScheduledScalings keep number scheduled scalings. */ /** @brief _numScheduledScalings keep number scheduled scalings. */
qint32 _numScheduledScalings; qint32 _numScheduledScalings;
virtual bool eventFilter(QObject* object, QEvent* event) Q_DECL_OVERRIDE;
void FictiveSceneRect(QGraphicsScene *sc, QGraphicsView *view);
}; };
/** /**