允许QGraphicsView移动到场景外

时间:2019-03-05 16:26:43

标签: c++ qt

我有一个派生类QGraphicsView,在其中我将拖动模式设置为ScrollHandDrag,还实现了缩放功能:

标题

#ifndef CUSTOMGRAPHICSVIEW_H
#define CUSTOMGRAPHICSVIEW_H

#include <QGraphicsView>

class CustomGraphicsView : public QGraphicsView
{
  Q_OBJECT
public:
  CustomGraphicsView(QWidget* parent = nullptr);

protected:
  virtual void wheelEvent(QWheelEvent* event) override;
};

#endif  // CUSTOMGRAPHICSVIEW_H

实施

#include "customview.h"

#include <QWheelEvent>

CustomGraphicsView::CustomGraphicsView(QWidget* parent) : QGraphicsView(parent)
{
  setScene(new QGraphicsScene);
  setDragMode(ScrollHandDrag);
}

void CustomGraphicsView::wheelEvent(QWheelEvent* event)
{
  // if ctrl pressed, use original functionality
  if (event->modifiers() & Qt::ControlModifier)
    QGraphicsView::wheelEvent(event);
  // otherwise, do yours
  else
  {
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    if (event->delta() > 0)
    {
      scale(1.1, 1.1);
    }
    else
    {
      scale(0.9, 0.9);
    }
  }
}

当我在程序中使用此类时(请参见下文),我可以在场景中四处移动并放大和缩小。但是,当图像在一个维度上大于视口时,但在另一维度上不大于视口时(请参见附图),我只能沿着与图像大于视口重合的轴拖动。在所附的图像中,这是垂直的,因为可以通过右侧滚动条看到它。

我的问题是:有没有一种方法可以限制移动?是否可以设置滚动模式以允许我自由移动,而不管视图中所包含的场景如何?我是重新实现mouseMoveEvent的唯一选择吗?

enter image description here

应用

#include <QApplication>
#include <QGraphicsPixmapItem>
#include "customview.h"

int main(int argc, char** argv)
{
  QApplication app(argc, argv);
  CustomGraphicsView cgv;
  QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(QImage("clouds-country-daylight-371633.jpg")));
  cgv.scene()->addItem(item);
  cgv.show();
  return app.exec();
}

我使用的图像是this one

1 个答案:

答案 0 :(得分:1)

仔细阅读documentation后,我的结论是不可能移出场景。但是,可以手动set the limits of the scene到比实际场景大的东西。最简单的解决方案是按照建议的here在开始时设置足够大的场景。但是,这不是动态的并且有局限性。我通过在场景更新时自动计算场景限制来解决此问题。为此,我将QGraphicsScene::changed连接到计算场景的自动大小的插槽,并手动强制通过鼠标移动来更新场景。具有所需行为的最后一堂课是:

标题

#ifndef CUSTOMGRAPHICSVIEW_H
#define CUSTOMGRAPHICSVIEW_H

#include <QGraphicsView>

class CustomGraphicsView : public QGraphicsView
{
  Q_OBJECT
public:
  CustomGraphicsView(QWidget* parent = nullptr);

protected:
  virtual void wheelEvent(QWheelEvent* event) override;
  virtual void mouseMoveEvent(QMouseEvent* event) override;
  virtual void mousePressEvent(QMouseEvent* event) override;
  virtual void mouseReleaseEvent(QMouseEvent* event) override;

  void autocomputeSceneSize(const QList<QRectF>& region);
};

#endif  // CUSTOMGRAPHICSVIEW_H

CPP

#include "customview.h"

#include <QWheelEvent>

CustomGraphicsView::CustomGraphicsView(QWidget* parent) : QGraphicsView(parent)
{
  // Set up new scene
  setScene(new QGraphicsScene);

  // Do not show scroll bars
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

  // Connect scene update to autoresize
  connect(scene(), &QGraphicsScene::changed, this, &CustomGraphicsView::autocomputeSceneSize);
}

void CustomGraphicsView::wheelEvent(QWheelEvent* event)
{
  // if ctrl pressed, use original functionality
  if (event->modifiers() & Qt::ControlModifier)
    QGraphicsView::wheelEvent(event);
  // Rotate scene
  else if (event->modifiers() & Qt::ShiftModifier)
  {
    if (event->delta() > 0)
    {
      rotate(1);
    }
    else
    {
      rotate(-1);
    }
  }
  // Zoom
  else
  {
    ViewportAnchor previous_anchor = transformationAnchor();
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    if (event->delta() > 0)
    {
      scale(1.1, 1.1);
    }
    else
    {
      scale(0.9, 0.9);
    }
    setTransformationAnchor(previous_anchor);
  }
}

void CustomGraphicsView::mouseMoveEvent(QMouseEvent* event)
{
  QGraphicsView::mouseMoveEvent(event);
  if (event->buttons() & Qt::LeftButton)
    // If we are moveing with the left button down, update the scene to trigger autocompute
    scene()->update(mapToScene(rect()).boundingRect());
}

void CustomGraphicsView::mousePressEvent(QMouseEvent* event)
{
  if (event->buttons() & Qt::LeftButton)
    // Set drag mode when left button is pressed
    setDragMode(QGraphicsView::ScrollHandDrag);
  QGraphicsView::mousePressEvent(event);
}

void CustomGraphicsView::mouseReleaseEvent(QMouseEvent* event)
{
  if (dragMode() & QGraphicsView::ScrollHandDrag)
    // Unset drag mode when left button is released
    setDragMode(QGraphicsView::NoDrag);
  QGraphicsView::mouseReleaseEvent(event);
}

void CustomGraphicsView::autocomputeSceneSize(const QList<QRectF>& region)
{
  Q_UNUSED(region);

  // Widget viewport recangle
  QRectF widget_rect_in_scene(mapToScene(-20, -20), mapToScene(rect().bottomRight() + QPoint(20, 20)));

  // Copy the new size from the old one
  QPointF new_top_left(sceneRect().topLeft());
  QPointF new_bottom_right(sceneRect().bottomRight());

  // Check that the scene has a bigger limit in the top side
  if (sceneRect().top() > widget_rect_in_scene.top())
    new_top_left.setY(widget_rect_in_scene.top());

  // Check that the scene has a bigger limit in the bottom side
  if (sceneRect().bottom() < widget_rect_in_scene.bottom())
    new_bottom_right.setY(widget_rect_in_scene.bottom());

  // Check that the scene has a bigger limit in the left side
  if (sceneRect().left() > widget_rect_in_scene.left())
    new_top_left.setX(widget_rect_in_scene.left());

  // Check that the scene has a bigger limit in the right side
  if (sceneRect().right() < widget_rect_in_scene.right())
    new_bottom_right.setX(widget_rect_in_scene.right());

  // Set new scene size
  setSceneRect(QRectF(new_top_left, new_bottom_right));
}
相关问题