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.

 

 

 

Advertisement

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s