0
votes

I have a QGraphicsScene, QGraphicsView and some QGraphicsItems subclassed. I want to track which item is under the cursor topmost visible. It works fine using hoverEnterEvent in most situations, but if I have two Objects where one is on top of another it does work on entering both but not on leaving the inner object (and re-entering the outer, since it never left the outer in the first place).

           +-------------------------------------+
  outside  |                                     |
           |  outer                              |
           |                                     |
           |                                     |
           |           +-------------+           |     +-------------+ 
           |           |             |           |     |             | 
           |           |             |           |     |   another   |
           |           |    inner    |           |     |             |
           |           |             |           |     |             |
           |           |             |           |     +-------------+ 
           |           +-------------+           |
           |                                     |
           |                                     |
           |                                     |
           |                                     |
           +-------------------------------------+

outside -> outer : works, outer is selected
outside -> outer -> outside -> another : works, first outside is selected, than nothing, than another
outer -> inner : works, inner is seletected
outside -> outer -> inner -> outer: does not work, first outside is selected, than inner, but than nothing (should be outer again)

What can I do, besides looping trough all graphicitems triggered via a slight delayed singleshot on hoverLeaveEvent?

Edit: I found a temporary solution: I added a global QList < MyQGraphicsItem *> where on MyQGraphicsItem::hoverEnterEvent I add "this", and on MyGraphicsItem::hoverLeaveEvent I remove the last item in the List. So the myGlobalQList.last() always contains the topmost item visible under the cursor. I assume this is not the best solution since QList is not threadsafe, therefor I am still interested in other solutions.

1
Your QList<QGraphicsItem*> solution isn't that bad after all - your QGraphicsScene isn't thread-safe itself, so you don't have to worry about QList. Semantically you'd use a QStack (LIFO), but generally I recommend to try using QGraphicsScene::itemAt(QPointF pos) instead. That's fast enough and you don't need to worry about keeping your QList up to date. - Martin Hennings
For us to answer your question more specifically, you really should explain what you want to achieve when you know the topmost item. - Martin Hennings

1 Answers

0
votes

Your QGraphicsItems live in a QGraphicsScene which can be displayed by one or more QGraphicsViews.

I know that the model-view mapping usually is 1:1.

Still I suggest to implement mouse handling like this in your view, not in the scene:

Install an eventFilter on your graphicsView->viewport().

Override the eventFilter() function in your filter class.

Watch for QEvent::MousePress, MouseMove, MouseRelease, maybe Enter and Leave, depending on what you need.

Probably you need to setMouseTracking(true) on the viewport.

Then, in the event filter function, use QGraphicsView::mapToScene() and QGraphicsScene::itemAt() to find the topmost item, or ::items() to find all items under the cursor.

I recently used this to decorate the topmost item with a border by painting over the view (QGraphicsView::drawForeground()).