Reputation: 31
I've got simple cpp code. I would like to move QGraphicsScene with mouse move:
// MainWindow.cpp code ------------------------------
void MainWindow::initializeMainViewWidget() {
/* some code */
itemsFrame->setLayout(layout);
mView = std::make_unique<ui::MainView>();
layout->addWidget(mView.get());
mScene = std::make_unique<ui::MainScene>();
mView->setScene(mScene.get());
QObject::connect(mScene.get(), &ui::MainScene::openItem, this, &MainWindow::openUpdateItemDialog);
mView->show();
}
// MainView.cpp code -------------------------------
void MainView::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::RightButton) {
// Store original position.
mPos0 = event->position(); //mPos0 is QPointF
event->accept();
setCursor(Qt::ClosedHandCursor);
return;
} else if (event->button() == Qt::LeftButton) {
event->ignore();
}
QGraphicsView::mousePressEvent(event);
}
void MainView::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
event->ignore();
} else if (event->buttons() & Qt::RightButton) {
QPointF trans = event->position() - mPos0;
mPos0 = event->position();
event->accept();
translate(trans.x(), trans.y());
return;
}
QGraphicsView::mouseMoveEvent(event);
}
But when I add item by: addItem(someQGraphicsItem);
Item is shown. I can drag it... but can't move scene with RMB and mouseMove.
Upvotes: 1
Views: 541
Reputation: 20161
I took my old sample from SO: Zoom functionality using Qt and added the code to pan the contents by mouse dragging:
#include <QtWidgets>
// class for widget to demonstrate zooming
class Canvas: public QGraphicsView {
// variables:
private:
// start position for pan
QPoint _posRMB;
// methods:
public:
// constructor.
Canvas() = default;
// destructor.
virtual ~Canvas() = default;
// disabled:
Canvas(const Canvas&) = delete;
Canvas& operator=(const Canvas&) = delete;
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent) override
{
if (pQEvent->button() == Qt::RightButton) {
_posRMB = pQEvent->pos();
pQEvent->accept();
setCursor(Qt::ClosedHandCursor);
}
}
virtual void mouseMoveEvent(QMouseEvent *pQEvent) override
{
if (pQEvent->buttons() & Qt::RightButton) {
// pos() -> virtual canvas, _posRMB -> virtual canvas
QPointF delta = mapToScene(pQEvent->pos()) - mapToScene(_posRMB);
// modify transform matrix
translate(delta.x(), delta.y());
_posRMB = pQEvent->pos();
// force update
update();
pQEvent->accept();
}
}
virtual void mouseReleaseEvent(QMouseEvent *pQEvent)
{
if (pQEvent->button() == Qt::RightButton) {
unsetCursor();
}
}
virtual void wheelEvent(QWheelEvent *pQEvent) override
{
//qDebug() << "Wheel Event:";
// pos() -> virtual canvas
QPointF pos = mapToScene(pQEvent->pos());
// scale from wheel angle
float delta = 1.0f + pQEvent->angleDelta().y() / 1200.0f;
// modify transform matrix
QTransform xform = transform();
xform.translate(pos.x(), pos.y()); // origin to spot
xform.scale(delta, delta); // scale
xform.translate(-pos.x(), -pos.y()); // spot to origin
setTransform(xform);
// force update
update();
pQEvent->accept();
}
};
QRectF toScr(QWidget *pQWidget, float x, float y, float w, float h)
{
const int wView = pQWidget->width(), hView = pQWidget->height();
const int s = wView < hView ? wView : hView;
return QRectF(
(0.5f * x + 0.5f) * s, (0.5f * y + 0.5f) * s,
0.5f * w * s, 0.5f * h * s);
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
Canvas canvas;
canvas.setTransformationAnchor(QGraphicsView::NoAnchor);
canvas.setDragMode(QGraphicsView::NoDrag);
canvas.resize(256, 256);
canvas.show();
// prepare scene
QGraphicsScene qGScene;
qGScene.addRect(toScr(canvas.viewport(), -1.0f, -1.0f, 2.0f, 2.0f), QColor(0x000000u));
qGScene.addRect(toScr(canvas.viewport(), -0.2f, -0.2f, 0.4f, 0.4f), QColor(0x00ff00u));
qGScene.addRect(toScr(canvas.viewport(), -0.8f, -0.8f, 0.4f, 0.4f), QColor(0xff0000u));
qGScene.addRect(toScr(canvas.viewport(), -0.8f, 0.4f, 0.4f, 0.4f), QColor(0x0000ffu));
qGScene.addRect(toScr(canvas.viewport(), 0.4f, 0.4f, 0.4f, 0.4f), QColor(0xff00ffu));
qGScene.addRect(toScr(canvas.viewport(), 0.4f, -0.8f, 0.4f, 0.4f), QColor(0xffff00u));
canvas.setScene(&qGScene);
// runtime loop
return app.exec();
}
Output:
I struggled a while to get it running as expected until I realized that
QPointF delta = mapToScene(pQEvent->pos() - _posRMB); // Not working!
isn't the same as
QPointF delta = mapToScene(pQEvent->pos()) - mapToScene(_posRMB);
Additionally, it's important to disable the auto-fit-to-view of QGraphicsView
:
canvas.setTransformationAnchor(QGraphicsView::NoAnchor);
While thinking again about OPs question, I became aware of another possible issue:
If the scene is smaller than the view, it's auto-aligned. (The QGraphicsView::alignment is involved.)
In my demo-session, I started with zoom-in, to prevent this issue.
Another option, to make the scene draggable even it's smaller than the view – the scene size can be tweaked by setting QGraphicsView::sceneRect explicitly.
While scrolling through the doc. of QGrapicsView I noticed:
dragMode : DragMode
This property holds the behavior for dragging the mouse over the scene while the left mouse button is pressed.
This property defines what should happen when the user clicks on the scene background and drags the mouse (e.g., scrolling the viewport contents using a pointing hand cursor, or selecting multiple items with a rubber band). The default value, NoDrag, does nothing.
This behavior only affects mouse clicks that are not handled by any item. You can define a custom behavior by creating a subclass of QGraphicsView and reimplementing mouseMoveEvent().
which I found worth to mention.
Upvotes: 1