Как да получавам известия от 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 не е опция.
  • wrap 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, вместо да наследявате от него. Този клас няма да предостави публичен достъп до изгледа, така че създателите на Items са принудени да извикат вашата собствена функция 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