Refire event while it is delivered is evil - always?!
Jeanette Winzenburg
fastegal at swingempire.de
Fri Nov 15 13:30:36 UTC 2019
*muttering to myself ..
Meanwhile, my understanding evolved a bit - there are actually two
refiring scenarios, both wrecking the event dispatch sequence, the
first more evil than the second
1. getParent.fireEvent(receivedKeyEvent) which leads to serious
misbehaviour (as reported f.i. in
https://bugs.openjdk.java.net/browse/JDK-8207759 ) - fix understood,
implemented and waiting for review
2. child.fireEvent(receivedKeyEvent) which leads to misbehavior (as
reported in https://bugs.openjdk.java.net/browse/JDK-8229924 ) - still
don't know how to fix it: the child will never get a keyEvent
"naturally" because it's never focusOwner. So the parent must deliver
it somehow .. Currently experimenting with custom implementation of
buildEventDispatchChain (append the editor's chain? or a custom
dispatcher doing so?)
More questions than answers ;)
-- Jeanette
Zitat von Jeanette Winzenburg <fastegal at swingempire.de>:
> While fixing https://bugs.openjdk.java.net/browse/JDK-8207759 it
> turned out that the underlying reason for the bug was a broken event
> dispatch sequence introduced by behavior.forwardToParent. Which is a
> call to parent.fireEvent with the event that was received. This
> builds a nested chain and delivers the event to all handlers in
> that new chain - down and up again - _before_ the current chain is
> completed. Consequently, the consuming singleton handler for the
> same event is notified _after_ the scene-level handlers (in
> particular the accelerators) have seen and handled it.
>
> Looks like it happens for any control (not only for a TextField as
> in the referenced issue, nor only for controls with a
> FakeFocusTextField which refire while processing keyEvents), as the
> example below demonstrates.
>
> My current understanding of event dispatch is, that a chain has a
> life-cycle consisting of separate (?) states:
>
> - building the chain from eventTargets
> - delivering the event along the dispatchers in the chain
>
> There's a contract for dispatch sequence (like capturing/bubbling
> phase, dispatch from specialized to super event types and other
> rules). That can be guaranteed as long as chain building and event
> delivering are separate phases, it seems to break down if they are
> mixed (there are other issues with a similar/same underlying reason,
> f.i. in all controls with a FakeFocusTextField).
>
> Now the questions:
>
> - is there any specification about not mixing the life-cycle states?
> if so, where?
> - or is there a way to safely re-fire an event at the moment of receiving it?
> - or maybe I got it all wrong, if so please guide me :)
>
> -- Cheers, Jeanette
>
>
> The example:
>
> public class NestedEventDispatchChain extends Application {
>
>
> private KeyCode key = DIGIT1;
> private Parent createContent() {
> Button button = new Button("the evil button!");
> // re-firing handler
> button.addEventHandler(KEY_PRESSED, e -> {
> if (key == e.getCode()) {
> System.out.println("before refire " + e);
> button.getParent().fireEvent(e);
> System.out.println("after refire " + e);
> }
> });
>
> // consuming singleton handler
> button.setOnKeyPressed(e -> {
> if (key == e.getCode()) {
> e.consume();
> System.out.println("consumed in singleton " + e.getCode());
> }
> });
> BorderPane content = new BorderPane(button);
> return content;
> }
>
> @Override
> public void start(Stage stage) throws Exception {
> Scene scene = new Scene(createContent());
> // accelerator that shouldn't be triggered because singleton
> handler consumed
>
> scene.getAccelerators().put(KeyCombination.keyCombination(key.getName()), ()
> -> {
> System.out.println("accelerator triggered for " + key);
> });
> stage.setScene(scene);
> stage.show();
> }
>
> public static void main(String[] args) {
> launch(args);
> }
> }
More information about the openjfx-dev
mailing list