Как получать уведомления от QGraphicsScene о addItem или itemChange?

В моем проекте я использую QGraphicsScene и добавляю/удаляю элементы по всему коду.

Теперь я хочу получать уведомления всякий раз, когда QGraphicsItem добавляется или удаляется. Многие классы Qt имеют сигналы уведомления или, по крайней мере, виртуальные функции, которые вызываются при таких изменениях. Я пытаюсь избежать добавления большого количества строк кода во многих местах, что не только громоздко, но и небезопасно (забыть о вставке/удалении сейчас или в будущем).

Мне нужно решение, которое работает с любым QGraphicsItem.

Это список вещей, которые не работают:

  • подключиться к сигналу QGraphicsScene (как в QAbstractItemModel::rowsInserted()) -> его нет.
  • наследовать от QGraphicsScene и перегрузить виртуальную функцию уведомления (как в QTabWidget::tabInserted()) -> ее нет.
  • наследовать и перегружать addItem(), отправляя уведомления самому (как в QMdiArea::addSubWindow()) -> addItem не является виртуальным и вызывается из конструкторов QGraphicsItems.
  • установить фильтры событий на недавно добавленный QGraphicsItems -> не знаю, как получить недавно добавленный элемент, И это будет sceneEventFilter, который можно установить только на другом QGraphicsItems.
  • подключение к itemChange() из QGraphicsItem -> itemChange не является сигналом, И перегрузка QGraphicsItem невозможна.
  • оберните QGraphicsScene (имея сцену как частный член) и выставьте только функции addItem и removeItem ->, но QGraphicsItems в этой сцене все еще может получить к ней доступ через функцию scene(), поэтому это решение недостаточно безопасно.

Как я могу получать уведомления об изменениях элементов?

Если есть простой способ, который я просто пропустил, пожалуйста, укажите мне на него. В противном случае я был бы очень признателен за идеи по этому поводу.


person Martin Hennings    schedule 22.10.2012    source источник
comment
Я думаю, что лучший способ - просто обернуть QGraphicsScene и предоставить свою собственную функцию addItem() в оболочке.   -  person pmr    schedule 22.10.2012
comment
Жаль, что вы не можете создать подкласс QGraphicsItem, так как все его изменения сцены (включая добавление/удаление сцены) выполняются через его метод sceneEvent(QEvent* event), который обеспечивает очень чистое и настраиваемое решение вашей проблемы.   -  person cmannett85    schedule 22.10.2012
comment
@pmr Как я уже сказал, функция addItem() не является виртуальной и вызывается из конструкторов QGraphicsItems. Так что это будет не полное решение.   -  person Martin Hennings    schedule 22.10.2012
comment
@ cmannett85 Мне также пришлось бы создать подкласс QGraphicsObject (который также используется), тем самым дублируя код. Хуже того, чтобы отправлять сигналы от QGraphicsItem, мне также пришлось бы наследоваться от QObject, что нарушает несколько иерархий наследования в моем проекте.   -  person Martin Hennings    schedule 22.10.2012
comment
Я думаю, что pmr имел в виду то, что вы могли бы написать класс, который содержит QGraphicsView, а не наследуется от него. Этот класс не предоставляет публичный доступ к представлению, поэтому создатели элементов вынуждены вызывать вашу собственную функцию addItem. Очевидно, что вы больше не можете предоставлять сцену через конструктор (потому что вы не можете получить() ее из своей оболочки), и вам придется изменить каждую строку, в которой элемент в данный момент добавляется к вашей сцене.   -  person Tim Meyer    schedule 22.10.2012
comment
@TimMeyer Это все равно было бы небезопасно, потому что QGraphicsItems, а также QGraphicsView знают свою сцену (), которая используется, например. для scene()->removeItem(this) - я все равно не смогу предотвратить это или, по крайней мере, получить уведомление об этом.   -  person Martin Hennings    schedule 22.10.2012


Ответы (2)


Я думаю, что лучшее, что вы можете сделать, это подключиться к сигналу QGraphicsScene::changed(). .

Он не скажет вам, какие элементы были изменены/добавлены/удалены, поскольку он предназначен для QGraphicsView для обновления отображения. Но вы должны быть в состоянии узнать, используя предоставленные регионы.

person Stephen Chu    schedule 22.10.2012

Я понимаю, что одно из требований 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)
person Rafe    schedule 22.01.2020