【问题标题】:How to keep the size and position of QGraphicsItem when scaling the view?缩放视图时如何保持 QGraphicsItem 的大小和位置?
【发布时间】:2017-03-28 05:04:38
【问题描述】:

我在 QGraphicsScene 中有一些 QGraphicsItems,它们在缩放时应该保持相同的大小和位置。我试过 QGraphicsItem::ItemIgnoresTransformations 但事实证明这些项目的位置错误。下面是一个示例代码:

我有这样的 QGraphicsView 子类:

class Graphics : public QGraphicsView
{
public:
    Graphics();
    QGraphicsScene *scene;
    QGraphicsRectItem *rect;
    QGraphicsRectItem *rect2;

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

在它的构造函数中:

Graphics::Graphics()
{
    scene = new QGraphicsScene;
    rect = new QGraphicsRectItem(100,100,50,50);
    rect2 = new QGraphicsRectItem(-100,-100,50,50);
    scene->addLine(0,200,200,0);

    rect->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
    scene->addItem(rect);
    scene->addItem(rect2);

    setScene(scene);
    scene->addRect(scene->itemsBoundingRect());
}

wheelEvent 虚函数:

void Graphics::wheelEvent(QWheelEvent *event)
{
    if(event->delta() < 0)
        scale(1.0/2.0, 1.0/2.0);
    else
        scale(2, 2);
    scene->addRect(scene->itemsBoundingRect());

    qDebug() << rect->transform();
    qDebug() << rect->boundingRect();
    qDebug() << rect2->transform();
    qDebug() << rect2->boundingRect();
}

原始视图如下所示: 1

以直线为道路,以直线为符号。缩小时,矩形保持其大小但跳出场景: 2

应该是矩形的左上角到线的中间。我也对显示 boundingRect 和 transform 保持不变的调试信息感到困惑,这似乎没有任何改变!是什么导致了问题,有什么办法可以解决吗?有人可以帮忙吗?谢谢!

【问题讨论】:

    标签: c++ qt qgraphicsitem


    【解决方案1】:

    抱歉耽搁了,现在我自己解决了问题。

    我发现QGraphicsItem::ItemIgnoresTransformations 仅在您要坚持的点位于项目坐标中的 (0,0) 时才有效。您还需要以这种方式手动更新 boundingRect 。尽管如此,我发现的最佳解决方案是子类 QGraphicsItem 并根据世界矩阵在paint() 中设置矩阵。下面是我的代码。

    QMatrix stableMatrix(const QMatrix &matrix, const QPointF &p)
    {
        QMatrix newMatrix = matrix;
    
        qreal scaleX, scaleY;
        scaleX = newMatrix.m11();
        scaleY = newMatrix.m22();
        newMatrix.scale(1.0/scaleX, 1.0/scaleY);
    
        qreal offsetX, offsetY;
        offsetX = p.x()*(scaleX-1.0);
        offsetY = p.y()*(scaleY-1.0);
        newMatrix.translate(offsetX, offsetY);
    
        return newMatrix;
    }
    

    还有绘画功能:

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                       QWidget *widget)
    {
         QPointF p(left, top);
         painter->setMatrix(stableMatrix(painter->worldMatrix(), p));
         painter->drawRect(left, top, width, height);
    }
    

    stableMatrix 的第二个参数是粘点,在我的示例代码中它位于项目的左上角。您可以将其更改为您的偏好。它真的很好用! 希望这篇文章有所帮助:)

    【讨论】:

      【解决方案2】:

      解决这个问题的方法更简单。

      QGraphicsItem::ItemIgnoresTransformations

      项目忽略继承的转换(即,它的位置仍然锚定到其父级,但忽略父级或视图旋转、缩放或剪切转换)。 [...]

      这就是关键! Item 忽略所有转换,但仍绑定到其父级。所以你需要两个项目:一个将保持相对位置(没有设置任何标志)的父项目和一个将在父母的(0,0)处进行绘图(设置QGraphicsItem::ItemIgnoresTransformations标志)的子项目em> 点。

      以下是十字准线的一些工作代码,它具有恒定的大小和旋转,同时保持与其父级的相对位置:

      #include <QGraphicsItem>
      #include <QPainter>
      
      class CrossHair : public QGraphicsItem
      {
      private:
          class CrossHairImpl : public QGraphicsItem
          {
          public:
              CrossHairImpl (qreal len, QGraphicsItem *parent = nullptr)
                  : QGraphicsItem(parent), m_len(len)
              {
                  setFlag(QGraphicsItem::ItemIgnoresTransformations);
              }
      
              QRectF boundingRect (void) const override
              {
                  return QRectF(-m_len, -m_len, m_len*2, m_len*2);
              }
      
              void paint (QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
              {
                  painter->setPen(QPen(Qt::red, 1));
                  painter->drawLine(0, -m_len, 0, m_len);
                  painter->drawLine(-m_len, 0, m_len, 0);
              }
      
          private:
              qreal m_len;
          };
      
      public:
          CrossHair (qreal x, qreal y, qreal len, QGraphicsItem *parent = nullptr)
              : QGraphicsItem(parent), m_impl(len, this)  // <-- IMPORTANT!!!
          {
              setPos(x, y);
          }
      
          QRectF boundingRect (void) const override
          {
              return QRectF();
          }
      
          void paint (QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override
          {
              // empty
          }
      
      private:
          CrossHairImpl m_impl;
      };
      

      【讨论】:

        猜你喜欢
        • 2021-04-27
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 2023-03-28
        • 2010-11-16
        相关资源
        最近更新 更多