如何在添加项或更改项时从QGraphicsScene获得通知?

12

在我的项目中,我正在使用 QGraphicsScene 并在代码中不断添加/删除项。

现在我想在 QGraphicsItem 被添加或移除时得到通知。许多 Qt 类都有通知信号或至少在这些更改时调用的虚拟函数。我试图避免在许多地方添加许多代码行,这既麻烦又不安全(现在或将来可能会忘记插入/删除)。

我需要一个适用于任何 QGraphicsItem 的解决方案。

以下是不起作用的内容清单:

  • 连接到 QGraphicsScene 的信号 (如 QAbstractItemModel::rowsInserted() 中的信号) -> 没有信号。
  • 继承自 QGraphicsScene 并重载虚拟通知函数 (如 QTabWidget::tabInserted() 中的函数) -> 没有此功能。
  • 继承并重载 addItem(),手动发送通知 (如在 QMdiArea::addSubWindow() 中的方式) -> addItem 不是虚拟的,并且在 QGraphicsItems 的构造函数中调用。
  • 在新添加的 QGraphicsItems 上安装事件过滤器 -> 不知道如何获取新添加的项,并且它将是一个只能安装在其他 QGraphicsItems 上的 sceneEventFilter
  • 连接到 QGraphicsItemitemChange() -> itemChange 不是信号,并且重载 QGraphicsItem 不可行。
  • 包装 QGraphicsScene(将场景作为私有成员),并仅公开函数 addItemremoveItem -> 但该场景中的 QGraphicsItems 仍然可以通过 scene() 函数访问它,所以这个解决方案还不够安全。

如何获得有关项目更改的通知?

如果有我错过的简单方法,请指出来。否则,我非常感谢有关此的想法。


我认为最好的方法就是包装QGraphicsScene并在包装器中提供自己的addItem()函数。 - pmr
真可惜不能对QGraphicsItem进行子类化,因为它的所有场景变化(包括场景的添加/移除)都通过它的sceneEvent(QEvent* event)方法实现 - 这为解决您的问题提供了一个非常简洁且可调节的解决方案。 - cmannett85
正如我所说, addItem() 函数不是虚函数,并且从 QGraphicsItem 的构造函数中调用。因此这不是一个完整的解决方案。 - Martin Hennings
@cmannett85 我必须子类化 QGraphicsObject(也在使用中),这样会导致代码重复。更糟糕的是,为了从 QGraphicsItem 发送信号,我还必须继承 QObject,这将打破我的项目中的几个继承层次结构。 - Martin Hennings
1
我认为pmr的意思是你可以编写一个包含QGraphicsView的类,而不是从它继承。该类将不会授予对视图的公共访问权限,因此Item的创建者被迫调用您自己的addItem函数。显然,您不能再通过构造函数提供场景(因为您无法从包装器中获取它),并且您必须更改当前添加到场景中的每个项目的每一行代码。 - Tim Meyer
1
@TimMeyer 这仍然是不安全的,因为QGraphicsItems以及QGraphicsView都知道它们的scene() - 例如用于scene()->removeItem(this) - 我仍然无法防止或至少得到通知。 - Martin Hennings
2个回答

2
我认为最好的方法是连接到QGraphicsScene::changed()信号。该信号不会告诉您哪些项目已更改/添加/删除,因为它旨在由QGraphicsView更新显示。但是,您应该能够使用提供的区域找出更改的内容。

1
我知道OP的要求之一是不要对该项进行子类化,但我希望这仍然有助于其他人。Qt正在发送事件来完成此操作,只需要扩展itemChange方法以“收到通知”。然后,您可以像此处的示例一样挂接回调方法,或提供信号或其他所需内容。 这是Python代码,但我相信C++也是同样的模式:
def itemChange(self, change, value):
    """
    Runs if this item has the `ItemSendsGeometryChanges` flag set.

    This doesn't "accept" any of the changes, it is only to add hooks.
    """
    if change == QtWidgets.QGraphicsItem.ItemSceneChange:
        # The value for this event is the scene. None means the item was removed.
        if value:
            self.onAddedtoScene(value)
        else:
            self.onRemovedFromScene()

    return super(SceneNodeBase, self).itemChange(change, value)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接