JavaFX 8: The keyboard events are not being processed if a scene has only shapes

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.

 

 

 

Advertisements

Tic-Tac-Toe in JavaFX

Finished writing the JavaFX chapters for the second edition of my Java 24 Hour Trainer. It included a sample code of the Tic-Tac-Toe game. The front end is done in FXML and the application logic is written in Java.

fig_19_18

Using FXML allows to substantially minimize the amount of Java code. This application has 200 lines of code, namely:

Tic-Tac-Toe.fxml: 45 lines
Main.java: 27 lines
TicTacToeContoller.java: 118 lines
application.css: 12 lines.

The FXML and CSS files can be created and modified by people who do not know Java at all (i.e. graphic designers). I haven’t implemented a couple of menus, which would add a couple of dozens lines to the code base. Pretty concise, isn’t it? The source code of the Tic-Tac-Toe project is available among other code samples at https://github.com/yfain/java24hourtrainer2ndedition. I’ve developed this in Eclipse IDE with the E(fx)clipse plugin that generated an initial project for me. At the time of this writing NetBeans 8 IDE has the best support of JavaFX followed by IntelliJ IDEA 14, and then goes Eclipse with E(fx)clipse plugin.