QT - 不能用 mouseMove 移动场景

时间:2021-04-26 09:49:48

标签: c++ qt qgraphicsview

我有简单的 cpp 代码。我想用鼠标移动 QGraphicsScene:

// 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);
}

但是当我通过以下方式添加项目时: addItem(someQGraphicsItem);

显示项目。我可以拖动它......但不能用RMB和mouseMove移动场景。

1 个答案:

答案 0 :(得分:1)

我从 SO: Zoom functionality using Qt 中获取了我的旧样本,并添加了通过鼠标拖动来平移内容的代码:

#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();
}

输出:

Demo Video (GIF animation)

我挣扎了一段时间才让它按预期运行,直到我意识到

QPointF delta = mapToScene(pQEvent->pos() - _posRMB); // Not working!

不一样

QPointF delta = mapToScene(pQEvent->pos()) - mapToScene(_posRMB);

此外,禁用 QGraphicsView 的自动适应视图很重要:

  canvas.setTransformationAnchor(QGraphicsView::NoAnchor);

在再次思考 OP 问题时,我意识到另一个可能的问题:
如果场景小于视图,它会自动对齐。 (涉及到 QGraphicsView::alignment。)

在我的演示会话中,我从放大开始,以防止出现此问题。

另一种选择,即使场景比视图小,也可以拖动场景 - 可以通过显式设置 QGraphicsView::sceneRect 来调整场景大小。


在滚动文档时。 QGrapicsView 我注意到:

QGraphicsView::dragMode

<块引用>

拖动模式:DragMode

该属性保存在按下鼠标左键时在场景上拖动鼠标的行为。

这个属性定义了当用户点击场景背景并拖动鼠标(例如,使用指向手形光标滚动视口内容,或使用橡皮筋选择多个项目)时应该发生的情况。默认值 NoDrag 什么也不做。

此行为仅影响未由任何项目处理的鼠标点击。您可以通过创建 QGraphicsView 的子类并重新实现 mouseMoveEvent() 来定义自定义行为。

我觉得值得一提。