【问题标题】:QGraphicsItem::itemChange notified for position change but not for size changeQGraphicsItem::itemChange 通知位置更改但不通知大小更改
【发布时间】:2016-10-20 19:14:31
【问题描述】:

我有一个派生自 QGraphicsEllipseItem 的类,我需要知道它的位置或大小何时发生任何变化。我用鼠标处理大小调整并调用 QGraphicsEllipse::setRect。

好的,所以我尽职尽责地覆盖了类中的 itemChange() 方法,然后在创建后小心地设置了 ItemSendsGeometryChanges 标志

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

我的主要代码创建其中之一,将其添加到场景中,然后尝试移动/调整其大小。

虽然我总是在椭圆上调用 setPos() 后收到通知,但在调用 setRect() 后我没有收到通知。我可以使用 setRect 来完全改变椭圆的几何形状,但我的 itemChange 覆盖永远不会被调用。没有任何标志。

现在显然更改项目的 rect 正在更改其几何形状,那么我错过了什么?

我应该设置其他标志吗?其他一些改变我应该使用的椭圆大小的方法?我可以覆盖其他一些虚拟通知?

【问题讨论】:

  • 首先,您的itemChange 的前3 行可以交换为qDebug() &lt;&lt; change;...其次,您期望QGraphicsItem::GraphicsItemChange 的值是多少?最接近的值是ItemTransformChangeItemScaleChange,但它们与一些不同的事物相关。您可以尝试通过setTransform 方法调整椭圆的大小,应该会收到其中一个。
  • 我想我希望 GraphicsItemChange 中有一些值可以涵盖这一点,因为它显然是对项目几何的更改,并且我专门设置了通知该几何更改的标志。如果仅将项目的位置视为其几何形状的一部分,则此通知中似乎存在明显差距。我可以随意移动椭圆,但似乎没有办法调整它的大小并收到通知

标签: qt


【解决方案1】:

问题是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。变换矩阵变化由标准QGraphicsitems 跟踪,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 跟踪项目转换和移动。

【讨论】:

  • 感谢您的回答。对我来说,应该能够收到有关项目几何更改的通知似乎没有任何意义,但是更改该几何很容易而无需任何通知。
  • @Joe 我们拥有我们所拥有的。 :) 另一种方法是继承QGraphicsItem 并根据需要实现此类方法。很容易实现自己的setRect,在这种情况下没有人会调用“错误”的不可通知的方法。
  • 是的,这基本上就是我所做的。我想这是我的 C++ 纯粹主义者/忧虑者。 QGraphicsEllipseItem::setRect 不是虚拟的。我不知道 QT 内部发生了什么。它是否曾经调用过该函数本身?我希望不会,否则我会有洞要塞……
  • 与其子类化QGraphicsEllipseItem(或QGraphicsRectItem 和其他形状项类),您可能会发现子类化QGraphicsItem 更实用。当我刚开始做这些时,我避免自己创作,因为我不想处理这幅画,但从长远来看,创作我想要的东西要容易得多,而不是试图绕过画作的局限性。内置形状项目类。它们非常适合学习或如果您的需求很简单,但从头开始制作自己的非常容易。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-18
  • 2013-06-20
  • 2021-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多