I would like to implement a free dragging functionality based on C++ Qt's graphics-view.
However, I need to achieve this without changing the sceneRect
and without using view->setDragMode(QGraphicsView::ScrollHandDrag)
, as some of my business logic relies on the sceneRect
for calculations.
Below is the code that can reproduce the issue I am currently facing while still running successfully.
view.h:
#include <QGraphicsView>
#include <QMouseEvent>
#include <QWheelEvent>
#include <qscrollbar.h>
class CView : public QGraphicsView
{
Q_OBJECT
public:
CView(QWidget* parent = nullptr) : QGraphicsView(parent) {
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
setResizeAnchor(QGraphicsView::AnchorUnderMouse);
}
protected:
void mousePressEvent(QMouseEvent* event) override {
if (event->button() == Qt::LeftButton) {
m_lastPos = event->pos();
}
QGraphicsView::mousePressEvent(event);
}
void mouseMoveEvent(QMouseEvent* event) override {
if (event->buttons() & Qt::LeftButton) {
QPoint delta = event->pos() - m_lastPos;
QRectF sceneRect = this->sceneRect();
sceneRect.translate(-delta);
this->setSceneRect(sceneRect);
ensureVisible(sceneRect);
m_lastPos = event->pos();
}
QGraphicsView::mouseMoveEvent(event);
}
void wheelEvent(QWheelEvent* event) override {
QPoint scrollAmount = event->angleDelta();
double scaleFactor = 1.15;
if (scrollAmount.y() > 0) {
scale(scaleFactor, scaleFactor);
}
else if (scrollAmount.y() < 0) {
scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
// QRectF sceneRect = this->sceneRect();
// QPointF viewCenter = mapToScene(viewport()->rect().center());
// sceneRect.moveCenter(viewCenter);
// this->setSceneRect(sceneRect);
event->accept();
}
private:
QPoint m_lastPos;
};
scene.h:
#include <QObject>
#include <QGraphicsScene>
class CScene : public QGraphicsScene
{
Q_OBJECT
public:
CScene() {}
protected:
void drawBackground(QPainter *painter, const QRectF &rect) override {
QGraphicsScene::drawBackground(painter, rect);
painter->fillRect(sceneRect(), Qt::black);
}
};
main.cpp:
#include "View.h"
#include "Scene.h"
#include <QApplication>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
CView* view = new CView;
view->resize(600, 500);
CScene* scene = new CScene;
scene->setSceneRect(0, 0, 300, 200);
view->setScene(scene);
view->show();
return a.exec();
}
I am encountering two issues:
When I start dragging the mouse, the view jumps (I noticed that if the scrollbars are not hidden, their values become the maximum. I'm not sure if this is due to a coordinate problem or because I added
ensureVisible(sceneRect)
in themouseMoveEvent
).If I embed the view into a widget and place a
QPushButton
inside the widget, when I click the button and callview->fitInView(sceneRect, Qt::KeepAspectRatio)
, the scene's position is not centered within the view.