teclado rueda reducido maximo hasta hacer dinamico desactivar con como c++ qt qgraphicsview

c++ - rueda - ya se ha reducido el zoom hasta el maximo autocad



QGraphicsView Acercar y alejar la imagen con la rueda del mouse (9)

Tengo una aplicación con una ventana de QGraphicsView en el centro de la pantalla. Quiero poder acercar y alejar la imagen con la rueda del mouse.

Actualmente, he vuelto a implementar QGraphicsView y QGraphicsView la función de desplazamiento del mouse para que no desplace la imagen (como lo hace de forma predeterminada).

void MyQGraphicsView::wheelEvent(QWheelEvent *event) { if(event->delta() > 0) { emit mouseWheelZoom(true); } else { emit mouseWheelZoom(false); } }

así que cuando me desplazo, estoy emitiendo una señal verdadera si la rueda del ratón hacia adelante es falsa si la rueda del ratón retrocede.

Luego conecté esta señal a una ranura (función de zoom, ver más abajo ) en la clase que maneja mis cosas de GUI. Ahora, básicamente, creo que mi función de zoom no es la mejor forma de hacerlo. He visto algunos ejemplos de personas que utilizan la función de evento de rueda superior para establecer escalas, pero realmente no pude encontrar una respuesta completa.

Así que, en lugar de eso, he hecho esto, pero no es perfecto de ninguna manera, así que estoy buscando que esto se modifique un poco o un ejemplo de trabajo utilizando la función de escala en la rueda.

Inicializo m_zoom_level a 0 en el constructor.

void Display::zoomfunction(bool zoom) { QMatrix matrix; if(zoom && m_zoom_level < 500) { m_zoom_level = m_zoom_level + 10; ui->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); matrix.scale(m_zoom_level, m_zoom_level); ui->graphicsView->setMatrix(matrix); ui->graphicsView->scale(1,-1); } else if(!zoom) { m_zoom_level = m_zoom_level - 10; ui->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); matrix.scale(m_zoom_level, m_zoom_level); ui->graphicsView->setMatrix(matrix); ui->graphicsView->scale(1,-1); } }

Como puede ver arriba, estoy usando un QMatrix y lo escala y lo configuro en la QMatrix Gráficos y el ancla de transformación en la parte inferior del mouse, pero a veces no funciona a la perfección si estoy desplazando cargas, solo comenzará a acercarse. (Lo que creo que tiene que ver con el bucle int sobre o algo así).

Como dije, la ayuda con este o un buen ejemplo de escala bajo el mouse sería genial.


Aquí está la versión de python que funciona para mí. Proviene de la combinación de respuestas de @Stefan Reinhardt y @rengel.

class MyQGraphicsView(QtGui.QGraphicsView): def __init__ (self, parent=None): super(MyQGraphicsView, self).__init__ (parent) def wheelEvent(self, event): # Zoom Factor zoomInFactor = 1.25 zoomOutFactor = 1 / zoomInFactor # Set Anchors self.setTransformationAnchor(QtGui.QGraphicsView.NoAnchor) self.setResizeAnchor(QtGui.QGraphicsView.NoAnchor) # Save the scene pos oldPos = self.mapToScene(event.pos()) # Zoom if event.delta() > 0: zoomFactor = zoomInFactor else: zoomFactor = zoomOutFactor self.scale(zoomFactor, zoomFactor) # Get the new position newPos = self.mapToScene(event.pos()) # Move scene to old position delta = newPos - oldPos self.translate(delta.x(), delta.y())


Aquí hay una solución usando PyQt:

def wheelEvent(self, event): """ Zoom in or out of the view. """ zoomInFactor = 1.25 zoomOutFactor = 1 / zoomInFactor # Save the scene pos oldPos = self.mapToScene(event.pos()) # Zoom if event.angleDelta().y() > 0: zoomFactor = zoomInFactor else: zoomFactor = zoomOutFactor self.scale(zoomFactor, zoomFactor) # Get the new position newPos = self.mapToScene(event.pos()) # Move scene to old position delta = newPos - oldPos self.translate(delta.x(), delta.y())


Aquí hay una versión condensada de la solución anterior; con solo el código que necesitas poner en el evento de la rueda. Esto funciona con / sin barras de desplazamiento en mi prueba, perfectamente;)

void MyGraphicsView::wheelEvent(QWheelEvent* pWheelEvent) { if (pWheelEvent->modifiers() & Qt::ControlModifier) { // Do a wheel-based zoom about the cursor position double angle = pWheelEvent->angleDelta().y(); double factor = qPow(1.0015, angle); auto targetViewportPos = pWheelEvent->pos(); auto targetScenePos = mapToScene(pWheelEvent->pos()); scale(factor, factor); centerOn(targetScenePos); QPointF deltaViewportPos = targetViewportPos - QPointF(viewport()->width() / 2.0, viewport()->height() / 2.0); QPointF viewportCenter = mapFromScene(targetScenePos) - deltaViewportPos; centerOn(mapToScene(viewportCenter.toPoint())); return; }


Después de mucha frustración, esto parece funcionar. El problema parece ser que la transform QGraphicsView no tiene nada que ver con su posición de desplazamiento, por lo que el comportamiento de QGraphicsView::mapToScene(const QPoint&) const depende tanto de la posición de desplazamiento como de la transformación. Tuve que mirar la fuente para que mapToScene entienda esto.

Con esto en mente, esto es lo que funcionó: recuerde el punto de la escena al que apunta el mouse, haga una escala, asigne ese punto de la escena a las coordenadas del mouse, luego ajuste las barras de desplazamiento para hacer que ese punto termine debajo del mouse:

void ZoomGraphicsView::wheelEvent(QWheelEvent* event) { const QPointF p0scene = mapToScene(event->pos()); qreal factor = std::pow(1.01, event->delta()); scale(factor, factor); const QPointF p1mouse = mapFromScene(p0scene); const QPointF move = p1mouse - event->pos(); // The move horizontalScrollBar()->setValue(move.x() + horizontalScrollBar()->value()); verticalScrollBar()->setValue(move.y() + verticalScrollBar()->value()); }


Es un poco tarde pero hoy caminé por lo mismo solo con Pyside, pero debería ser lo mismo ...

El enfoque es "muy simple", aunque me costó un poco de tiempo ... Primero, establezca todos los Anclajes en NoAnchor, luego tome el punto del volante, mapéelo a la escena, traduzca la escena con este valor, escala y finalmente tradúzcalo atrás:

def wheelEvent(self, evt): #Remove possible Anchors self.widget.setTransformationAnchor(QtGui.QGraphicsView.NoAnchor) self.widget.setResizeAnchor(QtGui.QGraphicsView.NoAnchor) #Get Scene Pos target_viewport_pos = self.widget.mapToScene(evt.pos()) #Translate Scene self.widget.translate(target_viewport_pos.x(),target_viewport_pos.y()) # ZOOM if evt.delta() > 0: self._eventHandler.zoom_ctrl(1.2) else: self._eventHandler.zoom_ctrl(0.83333) # Translate back self.widget.translate(-target_viewport_pos.x(),-target_viewport_pos.y())

Esta fue la única solución que funcionó para mi propósito. En mi humilde opinión es también la solución más lógica ...


La combinación de la solución de @veslam: s con el código Smooth Zoom de QT Wiki ( https://wiki.qt.io/Smooth_Zoom_In_QGraphicsView ) parece funcionar muy bien:

Fuente:

QGraphicsViewMap::QGraphicsViewMap(QWidget *parent) : QGraphicsView(parent) { setTransformationAnchor(QGraphicsView::NoAnchor); setResizeAnchor(QGraphicsView::NoAnchor); } void QGraphicsViewMap::wheelEvent(QWheelEvent* event) { wheelEventMousePos = event->pos(); int numDegrees = event->delta() / 8; int numSteps = numDegrees / 15; // see QWheelEvent documentation _numScheduledScalings += numSteps; if (_numScheduledScalings * numSteps < 0) // if user moved the wheel in another direction, we reset previously scheduled scalings _numScheduledScalings = numSteps; QTimeLine *anim = new QTimeLine(350, this); anim->setUpdateInterval(20); connect(anim, SIGNAL (valueChanged(qreal)), SLOT (scalingTime(qreal))); connect(anim, SIGNAL (finished()), SLOT (animFinished())); anim->start(); } void QGraphicsViewMap::scalingTime(qreal x) { QPointF oldPos = mapToScene(wheelEventMousePos); qreal factor = 1.0+ qreal(_numScheduledScalings) / 300.0; scale(factor, factor); QPointF newPos = mapToScene(wheelEventMousePos); QPointF delta = newPos - oldPos; this->translate(delta.x(), delta.y()); } void QGraphicsViewMap::animFinished() { if (_numScheduledScalings > 0) _numScheduledScalings--; else _numScheduledScalings++; sender()->~QObject(); }

Encabezamiento:

class QGraphicsViewMap : public QGraphicsView { Q_OBJECT private: qreal _numScheduledScalings = 0; QPoint wheelEventMousePos; public: explicit QGraphicsViewMap(QWidget *parent = 0); signals: public slots: void wheelEvent(QWheelEvent* event); void scalingTime(qreal x); void animFinished(); };


Simplemente puede usar la funcionalidad incorporada AnchorUnderMouse o AnchorViewCenter para mantener el enfoque con el mouse o en el centro. Esto funciona para mí en Qt 5.7

void SceneView::wheelEvent(QWheelEvent *event) { if (event->modifiers() & Qt::ControlModifier) { // zoom const ViewportAnchor anchor = transformationAnchor(); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); int angle = event->angleDelta().y(); qreal factor; if (angle > 0) { factor = 1.1; } else { factor = 0.9; } scale(factor, factor); setTransformationAnchor(anchor); } else { QGraphicsView::wheelEvent(event); } }


Tal zoom es un poco complicado. Déjame compartir mi propia clase para hacer eso.

Encabezamiento:

#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 Graphics_view_zoom : public QObject { Q_OBJECT public: Graphics_view_zoom(QGraphicsView* view); void gentle_zoom(double factor); void set_modifiers(Qt::KeyboardModifiers modifiers); void set_zoom_factor_base(double value); private: QGraphicsView* _view; Qt::KeyboardModifiers _modifiers; double _zoom_factor_base; QPointF target_scene_pos, target_viewport_pos; bool eventFilter(QObject* object, QEvent* event); signals: void zoomed(); };

Fuente:

#include "Graphics_view_zoom.h" #include <QMouseEvent> #include <QApplication> #include <QScrollBar> #include <qmath.h> Graphics_view_zoom::Graphics_view_zoom(QGraphicsView* view) : QObject(view), _view(view) { _view->viewport()->installEventFilter(this); _view->setMouseTracking(true); _modifiers = Qt::ControlModifier; _zoom_factor_base = 1.0015; } void Graphics_view_zoom::gentle_zoom(double factor) { _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(); } void Graphics_view_zoom::set_modifiers(Qt::KeyboardModifiers modifiers) { _modifiers = modifiers; } void Graphics_view_zoom::set_zoom_factor_base(double value) { _zoom_factor_base = value; } bool Graphics_view_zoom::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; } } } Q_UNUSED(object) return false; }

Ejemplo de uso:

Graphics_view_zoom* z = new Graphics_view_zoom(ui->graphicsView); z->set_modifiers(Qt::NoModifier);


Zoom más suave

void StatusView::wheelEvent(QWheelEvent * event) { const QPointF p0scene = mapToScene(event->pos()); qreal factor = qPow(1.2, event->delta() / 240.0); scale(factor, factor); const QPointF p1mouse = mapFromScene(p0scene); const QPointF move = p1mouse - event->pos(); // The move horizontalScrollBar()->setValue(move.x() + horizontalScrollBar()->value()); verticalScrollBar()->setValue(move.y() + verticalScrollBar()->value()); }