在图形视图中实现自由拖动场景。

huangapple go评论77阅读模式
英文:

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-&gt;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 &lt;QGraphicsView&gt;
#include &lt;QMouseEvent&gt;
#include &lt;QWheelEvent&gt;
#include &lt;qscrollbar.h&gt;
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-&gt;button() == Qt::LeftButton) {
m_lastPos = event-&gt;pos();
}
QGraphicsView::mousePressEvent(event);
}
void mouseMoveEvent(QMouseEvent* event) override {
if (event-&gt;buttons() &amp; Qt::LeftButton) {
QPoint delta = event-&gt;pos() - m_lastPos;
QRectF sceneRect = this-&gt;sceneRect();
sceneRect.translate(-delta);
this-&gt;setSceneRect(sceneRect);
ensureVisible(sceneRect);
m_lastPos = event-&gt;pos();
}
QGraphicsView::mouseMoveEvent(event);
}
void wheelEvent(QWheelEvent* event) override {
QPoint scrollAmount = event-&gt;angleDelta();
double scaleFactor = 1.15;
if (scrollAmount.y() &gt; 0) {
scale(scaleFactor, scaleFactor);
}
else if (scrollAmount.y() &lt; 0) {
scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
// QRectF sceneRect = this-&gt;sceneRect();
// QPointF viewCenter = mapToScene(viewport()-&gt;rect().center());
// sceneRect.moveCenter(viewCenter);
// this-&gt;setSceneRect(sceneRect);
event-&gt;accept();
}
private:
QPoint m_lastPos;
};

scene.h:

#include &lt;QObject&gt;
#include &lt;QGraphicsScene&gt;
class CScene : public QGraphicsScene
{
Q_OBJECT
public:
CScene() {}
protected:
void drawBackground(QPainter *painter, const QRectF &amp;rect) override {
QGraphicsScene::drawBackground(painter, rect);
painter-&gt;fillRect(sceneRect(), Qt::black);
}
};

main.cpp:

#include &quot;View.h&quot;
#include &quot;Scene.h&quot;
#include &lt;QApplication&gt;
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
CView* view = new CView;
view-&gt;resize(600, 500);
CScene* scene = new CScene;
scene-&gt;setSceneRect(0, 0, 300, 200);
view-&gt;setScene(scene);
view-&gt;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 the mouseMoveEvent).

  • If I embed the view into a widget and place a QPushButton inside the widget, when I click the button and call view-&gt;fitInView(sceneRect, Qt::KeepAspectRatio), the scene's position is not centered within the view.

答案1

得分: 0

我已经确定了问题的源头。

第一个问题确实是由于 ensureVisible(sceneRect) 函数引起的,该函数旨在确保给定的矩形在视图内可见。

关于第二个问题,通过调用 qDebug() &lt;&lt; viewportTransform(),我发现 m31m32(平移分量)发生了变化,导致了偏移问题。要解决这个问题,我只需要将 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() &lt;&lt; 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).

huangapple
  • 本文由 发表于 2023年6月26日 17:03:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76555168.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定