Unconsumed event handlers

John Hendrikx john.hendrikx at gmail.com
Tue Nov 12 13:02:25 UTC 2024


I think `discardUnconsumedEventHandlers` is still a bit unpredictable, 
as it would depend on handler order.

The user handler would need to be called *after* Skin/Behavior handlers 
for it to be able to always discard any ifUnconsumed callbacks.  If the 
Skin is replaced, then it will re-register handlers and those will then 
be called last...

Of course, if we change Behaviors to do their work in filters, then we 
could get this to work properly.

--John

On 10/11/2024 08:12, Michael Strauß wrote:
> In JavaFX, user code and skins share the same event system. Since
> invocation order is fundamentally important for events, this leads to
> a lot of problems when skins add event handlers to their controls.
> Assume user code adds an event handler to a control, and _then_ sets a
> skin that also adds an event handler for the same event. In this case,
> the user-provided handler is invoked first. If the skin is set
> _first_, the skin gets the first chance to handle the event (see also
> https://bugs.openjdk.org/browse/JDK-8231245).
>
> Prioritized event handlers might be a solution for this problem, but
> they are quite difficult to get right. Instead, I think we can get
> almost all of the benefits using a much simpler solution: unconsumed
> event handlers.
>
> We add a new method to the `Event` class:
>
>      <E extends Event> void ifUnconsumed(EventHandler<E> handler)
>
> When an event filter or an event handler receives an event, it calls
> the `ifUnconsumed` method with another event handler. Then, after both
> phases of event delivery have completed, the list of unconsumed event
> handlers associated with the event is invoked in sequence. Once an
> unconsumed event handler consumes the event, further propagation is
> stopped.
>
> Skins and their behaviors would then always use the unconsumed form of
> event handlers:
>
>      // inside a skin/behavior
>      control.addEventHandler(
>          KeyEvent.KEY_PRESSED,
>          e -> e.ifUnconsumed(event -> {
>              // act on the event
>          }));
>
> This allows user code to see an event during both the capture and
> bubble phases without any inteference of the skin or behavior. If user
> code doesn't consume the event, the skin or behavior gets to act on
> it.
>
> In addition to that, we add a second new method to the `Event` class:
>
>      void discardUnconsumedEventHandlers()
>
> Calling this method in an event handler allows user code to discard
> any unconsumed event handlers that have been registered prior. Let's
> consider an example where user code wants to prevent a control skin
> from acting on the ENTER key event, but it also doesn't want to
> consume the event. Adding an event handler to the control, and then
> calling `discardUnconsumedEventHandlers()` inside of the event handler
> achieves exactly that: it allows the ENTER key event to flow freely
> through the control without interacting with it, since its unconsumed
> event handlers will never be called.
>
> Here is the PR for this proposal: https://github.com/openjdk/jfx/pull/1633


More information about the openjfx-dev mailing list