QGraphicsItem::itemChange notified for position change but not for size change

时间:2016-10-20 19:14:32

标签: qt

I've got a class derived from QGraphicsEllipseItem in which I need to know when its position or size changes in any way. I handle resizing with a mouse and calls to QGraphicsEllipse::setRect.

OK, so I dutifully overrode the itemChange() method in the class and then was careful to set the ItemSendsGeometryChanges flag after creating it

// Returns a human readable string for any GraphicsItemChange enum value

inline std::string EnumName(QGraphicsItem::GraphicsItemChange e);

// Simple test ellipse class

class MyEllipse : public QGraphicsEllipseItem
{
public:
    MyEllipse(int x, int y, int w, int h) : QGraphicsEllipseItem(x, y, w, h)
    {
        setFlags(
            QGraphicsItem::ItemIsSelectable 
            | QGraphicsItem::ItemIsMovable 
            | QGraphicsItem::ItemSendsGeometryChanges);
    }


    // QGraphicItem overrides
    virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override
    {
        std::stringstream oss;
        oss << "ItemChange " << EnumName(change) << std::endl;
        OutputDebugString(oss.str().c_str());
        return __super::itemChange(change, value);
    }
};

My main code creates one of these, adds it to the scene and then tries moving/resizing it.

And while I do always receive notifications after calling setPos() on the ellipse, I get NO notification after calling setRect(). I can use setRect to completely change the ellipse's geometry but my itemChange override is never called. Not with any flags.

Now obviously changing the item's rect is changing its geometry, so what am I missing?

Is there some other flag I should set? Some other way to change the size of the ellipse I should use? Some other notification virtual I can override?

1 个答案:

答案 0 :(得分:2)

问题是QGraphicsItem的位置与QGraphicsEllipseItem的矩形无关。第一个是项目相对于其父项的位置,如果是NULL,则是它的场景。最后一个是相对于项目位置的的矩形,其中应绘制椭圆。场景和QGraphicsItem的核心不知道它的任何变化。

让我们来看看这个测试:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QGraphicsScene scene;
    QGraphicsView view(&scene);
    QGraphicsEllipseItem item(10, 20, 30, 40);
    scene.addItem(&item);

    qDebug() << item.pos() << item.scenePos() << item.boundingRect();
    item.setRect(110, 120, 30, 40);
    qDebug() << item.pos() << item.scenePos() << item.boundingRect();

    view.resize(500, 500);
    view.show();

    return app.exec();
}

输出是:

QPointF(0,0) QPointF(0,0) QRectF(9.5,19.5 31x41)
QPointF(0,0) QPointF(0,0) QRectF(109.5,119.5 31x41)

可能的出路:

  1. 使用setTransform。标准QGraphicsitem跟踪转换矩阵更改,itemChange将收到相应的更改。但我想非同一性矩阵会降低性能(不检查)。
  2. 实施您自己的功能,例如setRect,您将在其中手动跟踪几何体更改。
  3. 子类QGraphicsItem,而不是QGraphicsEllipseItem。在这种情况下,您可以通过规则执行可防止无法检查的几何体更改。它看起来像这样:

    class EllipseItem: public QGraphicsItem
    {
    public:
        // Here are constructors and a lot of standard things for
        // QGraphicsItem subclassing, see Qt Assistant.
        ...
    
        // This method is not related with QGraphicsEllipseItem at all.
        void setRect(const QRectF &newRect)
        {
            setPos(newRect.topLeft());
            _width = newRect.width();
            _height = newRect.height();
            update();
        }
    
        QRectF boundingRect() const override
        {
            return bRect();
        }
    
        void paint(QPainter * painter, const QStyleOptionGraphicsItem * option,
                   QWidget * widget = nullptr) override
        {
            painter->drawRect(bRect());
        }
    
    private:
        qreal   _width;
        qreal   _height;
    
        QRectF bRect() const
        {
            return QRectF(0, 0, _width, _height);
        }
    };
    

    您还应该跟踪项目转换并浏览QGraphicsItem::itemChange

相关问题