4

It seems there is an issue in setting focus (and handling keyboard events) on the JavaFX scenes that have only shapes (e.g. Rectangle, Circle, etc). Since formatting FXML is not easy at stackoverflow, I described the issue and a workaround in my blog: http://yakovfain.com/2015/02/13/javafx-8-the-keyboard-events-are-not-being-processed-if-a-scene-has-only-shapes/

I'd appreciate if someone could find a better solution or explain what do I do wrong.

Thanks

Yakov Fain
  • 11,972
  • 5
  • 33
  • 38

1 Answers1

2

This works for me.

The only change I made from Yakov's original solution is to remove the button work around hack and make the request focus call after the stage had been shown.

I think in Yakov's original implementation, the group containing the shapes was not shown on a stage at the time focus was requested for it - so it never got focus. By ensuring that we wait until the stage is displayed before requesting focus, everything works fine.

sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.Group?>
<?import javafx.scene.shape.Rectangle?>

<Group fx:id="theGroup" onKeyPressed="#keyHandler" focusTraversable="true"
       xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
       fx:controller="Controller">
  <Rectangle fill="BLUE" height="300.0" stroke="BLACK"
             strokeType="INSIDE" width="300.0"/>
</Group>

Main.java

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 {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("sample.fxml"));
        Parent root = loader.load();

        primaryStage.setScene(new Scene(root, 300, 300));
        primaryStage.show();

        Controller controller = loader.<Controller>getController();
        controller.focus();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Controller.java

import javafx.fxml.FXML;
import javafx.scene.Group;
import javafx.scene.input.KeyEvent;

public class Controller {
    @FXML
    private Group theGroup;

    public void keyHandler(KeyEvent event) {
        System.out.println("A Key was pressed");
    }

    public void focus() {
        theGroup.requestFocus();
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Thank you @jewelsea for giving me an idea to set the focus after showing the stage. I found a little simpler solution: just added one line in my original Main class right after showing the stage: root.requestFocus(); – Yakov Fain Feb 13 '15 at 22:23