PDA

View Full Version : Graphics View Event Propagation



pherthyl
10th August 2007, 19:10
This may be a basic question, but I'm really having trouble with mouse event propagation with Graphics View.

My problem is that I have a box with some text in it. So a QGraphicsItem with a QGraphicsTextItem as the child. Well the box tracks mouse hover events, but for some reason the QGraphicsTextItem swallows those events. So when the mouse is over the text item, my box doesn't get hover events. While I don't know why QGraphicsTextItem doesn't pass those events along (with NoTextInteraction set), it at least makes sense that the topmost item gets the events first.
Now when I set TextEditorInteraction on the QGraphicsTextItem, I can type and click the cursor around, but I can't click and drag to highlight text. Those events are passed on to the box, so I end up moving the box when I really want to select text instead. Also, the QGraphicsView mousePressed method seems to get called first, even though the mouse press occurred on a QGraphicsItem. Shouldn't the view only get the mouse press if it is ignored by all the QGraphicsItems that are under the mouse?

All in all I'm very confused about how events work in Graphics View. Any help would be greatly appreciated.

wysota
10th August 2007, 21:14
While I don't know why QGraphicsTextItem doesn't pass those events along (with NoTextInteraction set), it at least makes sense that the topmost item gets the events first.
It handles them by itself, so they don't get propagated. It's just it doesn't provide any interaction as you asked it not to.


Now when I set TextEditorInteraction on the QGraphicsTextItem, I can type and click the cursor around, but I can't click and drag to highlight text. Those events are passed on to the box, so I end up moving the box when I really want to select text instead.
Hard to explain that without knowing how your scene is set up. A small compilable example would help pinpoint the problem.


Also, the QGraphicsView mousePressed method seems to get called first, even though the mouse press occurred on a QGraphicsItem.
The item probably doesn't handle mouse press events, so they get propagated to the scene and then to the view.


Shouldn't the view only get the mouse press if it is ignored by all the QGraphicsItems that are under the mouse?
That's probably exactly what happens.


All in all I'm very confused about how events work in Graphics View. Any help would be greatly appreciated.
Events is one thing, interactions are another - your items probably have a Movable flag set, so all mouse move events cause items to be moved (that's why the box moves instead of the text being dragged).

pherthyl
10th August 2007, 21:57
Thanks for the reply.


It handles them by itself, so they don't get propagated. It's just it doesn't provide any interaction as you asked it not to.

So if I don't want the QGraphicsTextItem to swallow the hover events (it doesn't do anything with them anyway so I don't see why it doesn't ignore() them), do I have to install an event filter on it?


Events is one thing, interactions are another - your items probably have a Movable flag set, so all mouse move events cause items to be moved (that's why the box moves instead of the text being dragged).

Yeah, I understand that part, I just don't know why I'm getting the events in the first place. If TextEditorInteraction is set on the QGraphicsTextItem, then the text in it should be selectable by the mouse. In other words, shouldn't it be grabbing all the mouse events and not passing them on to its parent?
Basically what confuses me is that QGraphicsTextItem swallows the hover events (where I don't want it to) and then passes on the mouse press events (which I also don't want). If someone is clicking around in the QGraphicsTextItem, I don't want all those mouse events to be passed on to the parent of the text item.. If that makes any sense :)

pherthyl
10th August 2007, 22:32
If I add a QGraphicsTextItem to a scene, like so:

QGraphicsTextItem* ti = new QGraphicsTextItem("test");
ti->setTextInteractionFlags(Qt::TextEditorInteraction) ;
addItem(ti);

I can edit text fine with the keyboard, and clicking the mouse will move the cursor there. But click drag to highlight still doesn't work. The text item doesn't accept the event, so it just gets passed on to the scene and view, which then draws a rubberband. But no selection in the text item.

wysota
10th August 2007, 22:54
So if I don't want the QGraphicsTextItem to swallow the hover events (it doesn't do anything with them anyway so I don't see why it doesn't ignore() them), do I have to install an event filter on it?
No, subclass, reimplement the event handler in it and ignore() the event there. It'll get propagated to the parent then (but you won't be able to move the item using mouse).


Yeah, I understand that part, I just don't know why I'm getting the events in the first place. If TextEditorInteraction is set on the QGraphicsTextItem, then the text in it should be selectable by the mouse. In other words, shouldn't it be grabbing all the mouse events and not passing them on to its parent?
Maybe the movable flag is checked first? You'd have to look at the source code if the base implementation is called in the beginning or in the end of the handler...


Basically what confuses me is that QGraphicsTextItem swallows the hover events (where I don't want it to) and then passes on the mouse press events (which I also don't want). If someone is clicking around in the QGraphicsTextItem, I don't want all those mouse events to be passed on to the parent of the text item.. If that makes any sense :)
I don't know what your "box" item does, but maybe it'd be simpler to subclas QGraphicsTextItem and modify its behaviour so that it draws the frame?

pherthyl
11th August 2007, 18:22
No, subclass, reimplement the event handler in it and ignore() the event there. It'll get propagated to the parent then (but you won't be able to move the item using mouse).

Hmm, I tried this, but the event still does not get propagated to the parent. Very strange. I get the event in the QGraphicsTextItem subclass, and properly ignore() it, but it still never reaches the QGraphicsItem behind it.


I don't know what your "box" item does, but maybe it'd be simpler to subclas QGraphicsTextItem and modify its behaviour so that it draws the frame?

Well that wouldn't be easily possible, but I found a another way to work around the problems. Now I just set setHandlesChildEvents(true) on the parent item when I don't want the textitem to be editable, and when I do, I clear that flag. Selecting text with the mouse still doesn't work though. Maybe I'll start another thread for that problem to avoid confusion.

wysota
11th August 2007, 20:22
Hmm, I tried this, but the event still does not get propagated to the parent.
It's almost not possible. You might have done something wrong. The only possibility is that there is an event filter applied on the item and it handles the event instead of the regular handler.


Very strange. I get the event in the QGraphicsTextItem subclass, and properly ignore() it, but it still never reaches the QGraphicsItem behind it.
In that case there is no filter :) Is the graphics item behind it the parent of the text item?

pherthyl
12th August 2007, 01:53
It's almost not possible. You might have done something wrong.

Quite likely yes :)


In that case there is no filter :) Is the graphics item behind it the parent of the text item?

Yes. Does being the parent make events not propagate?

Gopala Krishna
12th August 2007, 08:04
hmm... looks quite confusing.. I had a look at the QGraphicsItem::sceneEvent() and i found this

bool QGraphicsItem::sceneEvent(QEvent *event)
{
if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents) {
if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverLeave
|| event->type() == QEvent::DragEnter || event->type() == QEvent::DragLeave) {
// Hover enter and hover leave events for children are ignored;
// hover move events are forwarded.
return true;
}
May be this is causing some side effect since you are igonoring the hover event. Not sure though. IMHO you should post a simple example. It will make us understand in a better way.

BTW did you try calling
QGraphicsTextItem::setAcceptHoverEvents(false);
EDIT: If you are doing the above there is no need to reimplement hoverEvent methods as far as i have understood.
Note that QGraphicsTextItem enables hover events while constructing.
Also call setAcceptHoverEvents(true) on your parent item otherwise the handlers are not called.
Its worth to have a look at the documentation of QGraphicsItem::setAcceptsHoverEvents ( )

Bitto
12th August 2007, 12:24
If someone can show a sample subclass that ignores the event, it'll be easier to see what's going on. The code in sceneEvent() is for filtering away enter and leave events for items that handle child events - it's a special thing for hover events to let you track the mouse motion over all children, avoiding having to check whether enter and leave events were for the parent or the child, or whatever :-). Hover events and mouse events are handled differently, though...

mooreaa
3rd July 2008, 11:39
Hmm I was confused by this for a while, but it looks like the parent object needs to have the flags:

setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);

in order for the text interaction to work right.