I kind of share Martin's sentiment. In my opinion, there are two general problems with the FX event dispatching:
1. general lack of predictability in the order of event handling which becomes a problem when skin gets replaced in Control 2. Event.isConsumed() debacle and the possibility of creating a malformed dispatcher by the application, something that should not be possible For #1, Michael tried adding event handling priorities, and I suggested to use the InputMap specifically for Controls (Andy), both of which did not get traction for various reasons. In Swing, this issue can easily be solved via removing and re-registering listeners at the right order via public API, if I remember correctly. We can't use that in FX because the listeners are not accessible to the application code. To me, either solution is fine (of course, I favor the InputMap one because it limits the number of effective priorities to a minimum required for the skins to function, since the application code can always add a listener at higher priority, and because the application code cannot use priorities given to skins, while at the same time allowing for custom skins). The main reason I dislike the idea of "default event handlers" is that it's a public API that can be misused by the application code and break the skins (if I read it correctly). The reason I mentioned #2 is that it is somewhat relevant to the discussion, as in "why do we need to write custom dispatchers at all?" There should be only two methods, in my opinion, one that dispatches an event that bubbles up (with filters and handlers), and one that sends an event to a single target Node and nothing else. <rant>Somehow, Swing got the Events right - it manages to dispatch one (1) event in total, and the dispatching stops once the event is consumed. The FX decided it needed to reinvent the wheel and leave multiple booby traps in the process.</rant> This isn't exactly rocket science, we should be able to figure something out. Maybe there is another option that will satisfy everyone? What do you think? -andy From: Martin Fox <[email protected]> Date: Friday, January 9, 2026 at 10:36 To: Michael Strauß <[email protected]> Cc: OpenJFX <[email protected]>, Andy Goryachev <[email protected]> Subject: [External] : Re: Default event handlers Default handlers might make sense for Control (it’s reasonable to assume that a behavior or skin may install handlers) but the rest of the system avoids using handlers and instead relies on custom dispatchers. It seems wrong to add calls for registering default handlers on Scene and Window when they make a point of not using handlers to begin with. Could we restrict this to Control? Or at the very least Node? If this was restricted to Control would we still make the call for registering a default handler public? For existing controls outside developers should only register primary handlers. The documentation for Event.preventDefault() doesn't mention what happens if it's called in a filter. Event.preventDefault() is only useful if a primary handler or filter wants to skip the default without consuming the event. This sounds reasonable but I can’t come up with a specific use case. Could you provide an example? It’s unfortunate that the only way for a handler to send information to a dispatcher is to attach it as state on the event (and it’s unfortunate that there's no good way to keep that state from bleeding over to another dispatcher). If we’re going through the trouble we should consider generalizing this and opening it up. For example, we could allow a handler or filter to attach an arbitrary object to the event for the dispatcher to retrieve. It’s worth thinking about (if only for a moment). On the flip side preventDefault() is well-defined and based on a web standard so it makes sense to add this bit even it’s only used by Control or Node. Martin On Jan 5, 2026, at 8:46 AM, Andy Goryachev <[email protected]> wrote: Michael: Does the new approach fix https://bugs.openjdk.org/browse/JDK-8231245 ? Thanks, -andy From: openjfx-dev <[email protected]> on behalf of Michael Strauß <[email protected]> Date: Thursday, December 25, 2025 at 02:49 To: openjfx-dev <[email protected]> Subject: Re: Default event handlers I've run into some problems while trying to make event handlers on skins only act when the event isn't consumed by user code. Consider a button that is nested in some hierarchy: scene --> root ----> button When the button receives a MOUSE_RELEASED event, it consumes the event and fires off an ACTION event. Doing that in a default handler is fine, but as as consequence, the MOUSE_RELEASED event won't be immediately consumed. Instead, it bubbles up the entire hierarchy before it is finally handled and consumed by the button in its default handler after the dispatch chain has completed. This is clearly not what we want, as it can potentially cause ancestors to act on the event, too. (By the way, this also rules out an event system where events are dispatched in prioritized capture/bubble phases.) I think what we need is quite a bit simpler. Default event handlers are still the way to go, but they shouldn't act across the entire dispatch chain. Instead, they should only act locally on a single event target: when a target receives an event, it first invokes its regular handlers. Then, if the event is still eligible for default handling, the default handlers are invoked. Skins and behaviors should always use default handlers, never regular handlers. In the example, the button would consume the MOUSE_RELEASED event in its default handler, which will prevent it from bubbling up the hierarchy. If user code adds an event handler to the button, the user handler will always be invoked first and gets to decide whether to consume the event (Event.consume()), prevent the default handler from running (Event.preventDefault()), or let it continue to flow. Using this simplified model, I've been able to switch over InputMap and ListenerHelper (and therefore almost all controls) to use default handling, and it seems to work pretty well. Here is a PR with the implementation: https://github.com/openjdk/jfx/pull/2022<https://urldefense.com/v3/__https://github.com/openjdk/jfx/pull/2022__;!!ACWV5N9M2RV99hQ!OnSepyYfvYeheRw8A-xyeweOQoUPembkgJ5KD2QjYVbJGVRN-iqEo4Smiq1ZXkQuvgntR64VLg5zARo7H4N4y5oXH34$>
