[Development] Input events handling ideas and feedback
Filippo Cucchetto
filippocucchetto at gmail.com
Fri Jul 1 09:38:11 CEST 2016
> if we had time to filter out all the good ideas from all the frameworks, we’d have a better chance of making ours the best. ;-)
Agreed :)
> Well we advertise that it’s a declarative language. We could make it even more that way, even if it’s not strictly necessary. Would it be more elegant?
Yes absolutely
> Well in my experience, handling clicks inside delegates works fine
Yes it works fine in the sense that you receive the event in the
delegate MouseArea. But if you received the click event that means
that you accepted the press event (given that the click is a composed
event) and this in turn imply that a view child MouseArea doesn't
receive the press event. This breaks selection in TreeViews or
TableViews (probably because the do not monitor childMouseEvents) and
in the delegate MouseArea there's no way to receive a click event
without "stealing" the press event.
> I think we could say that QQuickWindowPrivate::deliverInitialMousePressEvent() does tunnelling: it starts with the root and goes recursively _down_ through the children until the event is accepted (Handled in WPF terminology). But for each child recursively, it calls QQuickWindow::sendEvent(), which in the case of mouse events calls sendFilteredMouseEvent(item->parentItem(), item, e, &hasFiltered). And that goes recursively _up_ the parent hierarchy, calling childMouseEventFilter on any ancestor Item which has the filtersChildMouseEvents flag set. So it’s kindof like bubbling, but it happens before the real event handling in the leaf Item, rather than afterwards. And it happens multiple times per “target", which would be inefficient and redundant, so QSet<QQuickItem *> *hasFiltered is used to keep track of the items that have already had their chance at filtering. (Yeah, a fresh new QSet gets populated for every event. But it’s not the only case of that, either.) So that’s already rather like bubbling, but I'd worry about changing the order: WPF gives the “source” a chance to handle the event first, then the bubbling happens after; whereas QtQuick does sendFilteredMouseEvent first and then lets the Item have the event. That might be a big change to make. But then again, by the time the ListView’s drag threshold is exceeded, the MouseArea inside the delegate has already been the grabber for a while; so the grab must be canceled, and that involves sending another event to tell it that it was canceled. So if we did tunnelling followed by bubbling, we’d need to keep doing that, and maybe it would be OK.
I think that the childMouseEventFilter way of being called it's weird.
I would expect that if A and B are two nodes where B is higher in Z
stack, A::childMouseEventFilter should be called before B. Instead
from what you explain and by looking at the code it seems that the
deliverInitialMousePressEvent() first goes down the hierarchy and then
calls childMouseEventFilter from child to root (so
B::childMouseEventFilter will be called before A). Given that i think
that childMouseEventFilter it's basically tunneling in the WPF way (so
an handle where you can receive an event before it gets delivered to a
child).
> Then under WPF Input Events there is a tree of elements. Based on the explanation, I guess it does start with the root element and does tunnelling, but is that the first step or do they already know by magic that leaf #2 “raised” the event? How did they skip the step of tunnelling to leaf #1?
In pseudocode (and please skip the naive implementation) i think that
they basically do
let mouseEvent
let a = x in allItems() where if x.enabled and x.contains(mouseEvent.pos())
let b = a.sortByGlobalZOrder() // So if x is before y in b than x is
painted over y
// Here we know that b[0] will raise the event
for (x in b.reverse())
if (x.onPreviewMouseEvent(mouseEvent)
return
for (x in b)
if (x.handleAlreadyAcceptedEvents or not mouseEvent.accepted)
x.onMouseEvent(mouseEvent)
What i see it's that have the concepted of "raise" and "handle". So in
the example they first find the item that "raise" the event After that
by doing tunneling and later bubbling they will find the event that
accept it. Furthermore during the calls to handlers they propagate
some information about the previous item who has been called by doing
bubbling/tunneling and who raised the event.
> Aha… so bubbling doesn’t always occur:
For what i see bubbling always happen if the event has not been pre
filtered by tunneling. In this case the event bubble up until it gets
accepted. After being accepted the bubbling continue iff there'are
items who what to handle "AlreadyAccepted" events.
--
Filippo Cucchetto
More information about the Development
mailing list