英文:
Implementing freely dragging the scene in graphics-view
问题
我会帮你翻译代码部分,以下是翻译好的内容:
我想在基于C++ Qt的图形视图中实现自由拖动功能。
然而,我需要在不更改`sceneRect`并且不使用`view->setDragMode(QGraphicsView::ScrollHandDrag)`的情况下实现此功能,因为我的一些业务逻辑依赖于`sceneRect`进行计算。
以下是可以重现我目前遇到的问题但仍然成功运行的代码。
**view.h:**
```cpp
#include <QGraphicsView>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QScrollBar>
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 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.
答案1
得分: 0
我已经确定了问题的源头。
第一个问题确实是由于 ensureVisible(sceneRect)
函数引起的,该函数旨在确保给定的矩形在视图内可见。
关于第二个问题,通过调用 qDebug() << viewportTransform()
,我发现 m31
和 m32
(平移分量)发生了变化,导致了偏移问题。要解决这个问题,我只需要将 m31 和 m32 设置为 0。可以通过使用 QGraphicsView::setSceneRect(0, 0, width, height)
来实现这一点。
英文:
I have identified the source of the problem.
The first issue indeed occurred due to the ensureVisible(sceneRect)
function, which aims to ensure that the given rectangle is visible within the view.
Regarding the second issue, by calling qDebug() << viewportTransform()
, I discovered that m31
and m32
(the translation components) have changed, resulting in the offset problem. To resolve this issue, all I need to do is set m31 and m32 to 0. This can be achieved by using QGraphicsView::setSceneRect(0, 0, width, height)
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论