缩放视图时如何保持QGraphicsItem的大小和位置?

时间:2016-11-14 14:14:58

标签: c++ qt qgraphicsitem

我在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

将该线作为道路并将其作为符号放在旁边。缩小时,rect保持其大小但跳出场景: 2

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

2 个答案:

答案 0 :(得分: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的第二个参数是标点,在我的示例代码中它是项目的左上角。您可以根据自己的喜好进行更改。它工作得很好! 希望这篇文章有所帮助:)

答案 1 :(得分:0)

解决方案更简单。

  

的QGraphicsItem :: ItemIgnoresTransformations

     

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

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

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

#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;
};
相关问题