Разрешить QGraphicsView перемещаться за пределы сцены

Я считаю, что то, что вы испытываете, - это что-то известное как Closure http://en.wikipedia.org/wiki/Closure_ (computer_science) . Ваша lamba имеет ссылку на переменную, которая находится вне самой функции. Ваш lamba не интерпретируется до тех пор, пока вы его не вызовите, и как только он получит значение, которое имеет переменная во время выполнения.

1
задан apalomer 5 March 2019 в 16:36
поделиться

1 ответ

После тщательного прочтения документации я пришел к выводу, что невозможно выйти за пределы сцены. Тем не менее, можно вручную установить пределы сцены на нечто большее, чем фактическая сцена. Самое простое решение состоит в том, чтобы установить достаточно большую сцену в начале, как предложено здесь . Однако это не динамично и имеет ограничения. Я решил эту проблему путем автоматического вычисления пределов сцены при каждом обновлении сцены. Для этого я подключаю 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));
}
0
ответ дан apalomer 5 March 2019 в 16:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: