I ran into an interesting problems with JavaFX. When the GUI is done in FXML it seems that if a scene has only shapes (e.g. Rectangle, Circle, etc.) the handler method doesn’t receive keyboard events. And the problem seems to be that there is no way (at least I don’t see it) to give a focus to such a scene. I found a workaround, but I’d appreciate if someone could offer a cleaner solution or confirm that this is a JavaFX bug.
Here’s a code sample that illustrates the problem and the solution:
1. Here is the main application:
package sample; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage primaryStage) throws Exception{ Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); primaryStage.setScene(new Scene(root, 300, 300)); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
2. Here’s the sample.fxml that works, except I don’t need a Button there:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?> <?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.shape.*?> <?import javafx.scene.control.Button?> <?import javafx.scene.Group?> <Group fx:id="theGroup" onKeyPressed="#keyHandler" focusTraversable="true" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller"> <children> <Button /> <Rectangle fill="BLUE" height="300.0" stroke="BLACK" strokeType="INSIDE" width="300.0" /> </children> </Group>
3. Here’s the Controller.java:
package sample; import javafx.fxml.FXML; import javafx.scene.Group; import javafx.scene.input.KeyEvent; public class Controller { @FXML Group theGroup; public void initialize(){ theGroup.setFocusTraversable(true); // doesn't have any effect theGroup.requestFocus(); // doesn't have any effect } public void keyHandler(KeyEvent event){ System.out.println("A Key was pressed"); } }
This application works and prints the message “A Key was pressed” as long as I keep the <Button> tag in FXML (it’s not visible on GUI because the Rectangle covers it). This is my workaround to make sure that event handler works and prints the message. Remove the <Button> tag from FXML, and the application won’t process the keyboard events. The problem seems to be that if the FXML has only shapes, it can’t get the focus. The code in the initialize() method doesn’t help to set the focus on a Group container.If anyone could find an explanation of why this code doesn’t work without a <Button>, please let me know.
Update: The user jewelsea on Stack Overflow suggested to set the focus after calling primaryStage.show(); http://stackoverflow.com/questions/28506855/javafx-8-the-keyboard-events-are-not-being-processed-if-a-scene-has-only-shapes.
This gave me an idea how to do it. I’ve added one line root.requestFocus(); at the end of the start() method. No <Button> is needed in FXML and no initialize() method is needed in the Controller.
One thought on “JavaFX 8: The keyboard events are not being processed if a scene has only shapes”