I want to listen to some KeyEvent in my scene, say KeyCode.ESCAPE
(close the scene when pressed).
scene.addEventHandler(KeyEvent.ANY, event -> {
if (event.isConsumed())
return;
switch (event.getCode()) {
case ESCAPE:
stage.hide();
event.consume();
break;
default:
break;
}
});
Now, the nodes inside the scene could have listened to ESCAPE
too.
// ....
someOtherNode.addEventHandler(KeyEvent.ANY, e -> {
if (e.getCode() == KeyCode.ESCAPE) {
// do stuff
e.consume();
}
});
// ....
How do I make sure that the KeyEvent
will be consumed from the node and not the scene?
Based on the diagram from Oracle, A workaround would be adding a dummy Node
at the end of the Node hierarchy that listens to KeyCode
s
But is there a better solution, like inverting the propagation route?
EDIT:
The use case:
A popup-like node that blocks other nodes would need to listens to the ESC key or focusProperty()
so that it can close itself.
Maybe you could loop over all nodes after catching the event in the scene to find out which node has actual focus? Then you could call node method to close?
There's two ways you can affect events:
Use the
Node.addEventFilter(...)
method to register a filter. A filter will execute on the capturing phase of the event (as the window is getting more specific, determining which Nodes should get the event).Use the
Node.addEventHandler(...)
method to register a handler. The handler will execute starting at the most specific node found in the capturing phase, heading down until it is consumed.So in the capturing phase, a stack is created. Starting with the window (topmost parent), each node that this event could potentially execute on is added to the stack (ending with the bottom most child). A filter can interrupt this process, or just execute an event during this process.
In the bubbling phase, the event handlers will start firing from the top of the stack (created in the capturing phase) until the stack is empty or the event is consumed.
In your case, you really shouldn't have anything to worry about. If any node cares about processing the "ESC" event, they will do so in the bubbling phase (and they should consume the event to prevent further processing). You can see this behavior in the
ComboBox
. If they don't care, it will bubble up to yourScene
and that handler will execute. Just make sure any custom code you create that processes an "ESC" press also consumes that event.For more information, there is a explanation and tutorial here: http://docs.oracle.com/javafx/2/events/jfxpub-events.htm
And here is some sample code demonstrating the Escape functionality. Pressing ESC while focused on the
ComboBox
will not cause the application to close, while it will close with the other controls.