How can I change the scene By pressing a specific key(b) on the the keyboard?

In my application, there are two scenes: mainScene and bossScene where mainScene is used when starting up the application.

  • I'm trying to implement the boss key functionality where by pressing the 'b' key on the the keyboard should change the scene to bossScene. And also by pressing the button in bossScene should switch back to mainScene.

    I'm getting an error on InteliJ saying "Cannot resolve method setOnKeyPressed in List

My Code:

 public void start(Stage stage) throws Exception { stage.setTitle("BossKey Example"); // Scene and layout for the main view VBox root = new VBox(); Scene mainScene = new Scene(root, 500, 300); // Scene for the BOSS view Scene bossScene = new Scene(new Label("Nothing suspicious here"), 500, 300); List<TextField> fields = new ArrayList<TextField>(); for (int i = 0; i < 10; i++) { fields.add(new TextField()); } fields.setOnKeyPressed(new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent keyEvent) { switch (keyEvent.getCharacter()){ case "b": stage.setScene(bossScene); break; } } }); 

/////// Added addEventFilter, still not working

 mainScene.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent() { @Override public void handle(KeyEvent keyEvent) { switch (keyEvent.getCharacter()){ case "b": stage.setScene(bossScene); break; } keyEvent.consume(); } }); // Create components for main view root.getChildren().addAll(fields); root.getChildren().add(new Button("Hello!")); stage.setScene(mainScene); stage.show(); } 

}

6

1 Answer

KeyCombination filters

You should use a key combination in an event filter, e.g., CTRL+B or SHORTCUT+B.

For details on how to apply key combinations, see:

Why a key combination is superior to filtering on the character "b":

  • If you filter on a "b" character, the feature won't work if caps lock is down.
  • If you filter on a "b" character, you will be unable to type "b" in the text field.

You might think you could write scene.setOnKeyPressed(...), however, that won't work as expected in many cases. A filter is required rather than a key press event handler because the key events may be consumed by focused fields like text fields if you use a handler, so a handler implementation might not activate in all desired cases.

Filtering on a key combination avoids the issues with trying to handle a character key press. The key combinations rely on key codes which represent the physical key pressed and don't rely on the state of other keys such as caps lock unless you explicitly add additional logic for that.

If you don't understand the difference between an event filter and an event handler and the capturing and bubbling phases of event dispatch, then study:

KeyCombination filter implementation

final EventHandler<KeyEvent> bossEventFilter = new EventHandler<>() { final KeyCombination bossKeyCombo = new KeyCodeCombination( KeyCode.B, KeyCombination.CONTROL_DOWN ); public void handle(KeyEvent e) { if (bossKeyCombo.match(e)) { if (stage.getScene() == mainScene) { stage.setScene(bossScene); } else if (stage.getScene() == bossScene) { stage.setScene(mainScene); } e.consume(); } } }; mainScene.addEventFilter(KeyEvent.KEY_PRESSED, bossEventFilter); bossScene.addEventFilter(KeyEvent.KEY_PRESSED, bossEventFilter); 

Accelerator alternative

An accelerator could be used instead of an event filter. Information on applying an accelerator is also in an answer to the linked question, I won't detail this alternative further here.

Example Solution

toboss

fromboss

Standalone executable example code:

import javafx.application.Application; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.input.*; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; import java.io.IOException; public class SceneSwap extends Application { @Override public void start(Stage stage) throws IOException { final Scene mainScene = new Scene( createLayout( "Press CTRL+B to enter boss mode", Color.PALEGREEN ) ); final Scene bossScene = new Scene( createLayout( "Press CTRL+B to exit boss mode", Color.PALEGOLDENROD ) ); final EventHandler<KeyEvent> bossEventFilter = new EventHandler<>() { final KeyCombination bossKeyCombo = new KeyCodeCombination( KeyCode.B, KeyCombination.CONTROL_DOWN ); public void handle(KeyEvent e) { if (bossKeyCombo.match(e)) { if (stage.getScene() == mainScene) { stage.setScene(bossScene); } else if (stage.getScene() == bossScene) { stage.setScene(mainScene); } e.consume(); } } }; mainScene.addEventFilter(KeyEvent.KEY_PRESSED, bossEventFilter); bossScene.addEventFilter(KeyEvent.KEY_PRESSED, bossEventFilter); stage.setScene(mainScene); stage.show(); } private VBox createLayout(String text, Color color) { VBox mainLayout = new VBox(10, new Label(text), new TextField() ); mainLayout.setPadding(new Insets(10)); mainLayout.setStyle("-fx-background: " + toCssColor(color)); return mainLayout; } private String toCssColor(Color color) { int r = (int) Math.round(color.getRed() * 255.0); int g = (int) Math.round(color.getGreen() * 255.0); int b = (int) Math.round(color.getBlue() * 255.0); int o = (int) Math.round(color.getOpacity() * 255.0); return String.format("#%02x%02x%02x%02x" , r, g, b, o); } public static void main(String[] args) { launch(); } } 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like