代码之家  ›  专栏  ›  技术社区  ›  apalomer

QGraphicsView移入外部场景

  •  0
  • apalomer  · 技术社区  · 5 年前

    我有一个派生类 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 .

    0 回复  |  直到 5 年前
        1
  •  2
  •   apalomer    5 年前

    在仔细阅读了 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
    

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