-1

So I want to do a title Menu for a video game project for college. I want to display a message press any key to continue... then when the user pressed any key, including the mouse, a method would run to set the stage to the next menu.

enter image description here

I posted all the relevant code bellow but short version is:

  • BackgroundImangeDisplayPane extends display pane and adds a background image.
  • TitleCard extends BackgroundImangeDisplayPane adds a VBox and 2 labels to the VBox
  • I'm using public void start(Stage primaryStage) throws Exception as the main, I set the setOnActionxxx methods here

I have tried using the set on action method on root and Vbox and non of them work... when I click nothing happens... But when I resize the window The root.setOnActionXXX "activates".

If I write the setOnAction methods on the TitleCard class It kind of works but then I cant switch the stage.

I will post the code bellow as well an explanation of the Scene structure its not to complicated:


// this will be the borderpane for every scene it recives a backgund 
//images that will be present in every menu
public BackgroundImangeDisplayPane() {
        try {
            stream = new FileInputStream(imagePath.toString());
            Image image = new Image(stream);
            ImageView imageView = new ImageView();
            imageView.setImage(image);
            imageView.setFitWidth(1920);
            imageView.setPreserveRatio(true);
            this.getChildren().add(imageView);

            BackgroundSize backgoundSize = new BackgroundSize(AUTO, AUTO, true, true, true, true);
            BackgroundImage backgroundImage = new BackgroundImage(image, NO_REPEAT, NO_REPEAT, CENTER, backgoundSize);
            Background background = new Background(backgroundImage);
            this.setBackground(background);

        } catch (Exception e) {

        }
    }


//This extends `BackgroundImangeDisplayPane` and places on top of it a A Vbox with two lables: the title and "press any key to continue..."
// it then adds styles to the labels
public class TitleCard extends BackgroundImangeDisplayPane {
    Label title = new Label("Boats & Docks"); // lable 1
    Label subtitle = new Label("Press any key to continue ..."); label2
    
    public TitleCard(){
        super();
        VBox vbox = new VBox();
        vbox.getChildren().add(title);
        vbox.getChildren().add(subtitle);
        
        this.setCenter(vbox);
        this.setAlignment(vbox, Pos.CENTER);
        vbox.setAlignment(Pos.CENTER);
        title.setFont(new Font(170)); // set to Label
        title.setTextFill(Color.SNOW);
        title.setEffect(new DropShadow());
        subtitle.setFont( new Font (30));
          
    }
}

... 
//Works as the "main" in javaFX
private Stage primaryStage;

    @Override
    public void start(Stage primaryStage) throws Exception {

        TitleCard root = new TitleCard();
        /*BasicMenu menu = new BasicMenu(5);
        menu.ButtonSetOnAction(0, e -> changeScene() );
        BackgroundImangeWithCustomMenu background = new 
        BackgroundImangeWithCustomMenu(menu,50,50);
        root.setCenter(background);*/
        Button b = new Button();
        b.setOnAction(e -> changeSceneToLoginMenu());
        System.out.println(root.getChildren().get(1).getClass());
        root.getChildren().get(1).setFocusTraversable(true);
        root.getChildren().get(1).setOnMouseClicked(e -> changeSceneToLoginMenu());
        root.getChildren().get(1).setOnKeyPressed(e -> changeSceneToLoginMenu());
        root.getChildren().get(0).setOnMouseClicked(e -> changeSceneToLoginMenu());
        root.getChildren().get(0).setOnKeyPressed(e -> changeSceneToLoginMenu());
/*
        root.setOnMouseClicked(e -> changeSceneToLoginMenu());
        root.setOnKeyReleased(e -> changeSceneToLoginMenu());
        root.setOnKeyPressed(e -> changeSceneToLoginMenu());
*/
        Scene scene = new Scene(root, 1280, 720);
        primaryStage.setScene(scene);
        primaryStage.show();

        this.primaryStage = primaryStage;

    }

  • My honest opinion is that JavaFX or Java Swing are the wrong tools for something like a video game. Look at something like LWJGL or LibGDX for Java game development. (As for your actual question, I'm going to have to look, it's tricky at best.) – markspace Sep 04 '21 at 22:16
  • 1
    Here are some potential answers I found on SO: https://stackoverflow.com/questions/29962395/how-to-write-a-keylistener-for-javafx – markspace Sep 04 '21 at 22:18
  • Can't its a college project. – Carlos Martins Sep 04 '21 at 22:18
  • What does that have to do with anything? Those aren't commercial products, they're free open source frameworks. – markspace Sep 04 '21 at 22:19
  • Here's a post on event handlers: https://docs.oracle.com/javafx/2/events/handlers.htm – markspace Sep 04 '21 at 22:23
  • [mcve] please .. and keep the tags focused - javafx2 certainly is _not_ the version you are using – kleopatra Sep 04 '21 at 22:52
  • @markspace College projects, by which I assume the OP means a homework assignment/class project (instead of e.g. a research project), often have relatively strict requirements regarding what you can and can't use. – Slaw Sep 04 '21 at 22:54
  • 2
    Register a key listener with the scene. – James_D Sep 05 '21 at 00:10

2 Answers2

0

As proposed by James in comments, when a key is pressed on the scene, navigate to the next scene (or replace the root in the current scene, and remove the key press handler).

scene.setOnKeyPressed(e -> navigateToNextScene());
jewelsea
  • 150,031
  • 14
  • 366
  • 406
-2

I managed to find a very simple working solution but I don't fully undestand why it does work. I Noticed that if I set the handler in the same class the node was instanciated the handler would work fine But if I tried to get the node with a method to the main fuction via root.getChildren().get(1) and then cast it to the VBox element the handler would not work.

As a solution I made the VBox a field and wrote a setter method for the VBox event Handler in the TitleCard Class. This fixed the problem.

I marked the code added as solution code with comments


public class TitleCard extends BackgroundImangeDisplayPane {
    
    Label title = new Label("Boats & Docks"); // lable 1
    Label subtitle = new Label("Press any key to continue ..."); label2
    VBox vbox = new VBox; // solution code
    
public TitleCard(){
        super();
        VBox vbox = new VBox();
        vbox.getChildren().add(title);
        vbox.getChildren().add(subtitle);
        
        this.setCenter(vbox);
        this.setAlignment(vbox, Pos.CENTER);
        vbox.setAlignment(Pos.CENTER);
        title.setFont(new Font(170)); // set to Label
        title.setTextFill(Color.SNOW);
        title.setEffect(new DropShadow());
        subtitle.setFont( new Font (30));
          
    }
// Solution Code
public void setVBoxHandler(EventHandler<? super MouseEvent> value){
      vbox.setOnMouseClicked(value); 
 }
}

Then I set the handler in the start method:

public void start(Stage primaryStage) throws Exception {

        TitleCard root = new TitleCard();
        VBox vBox =(VBox) root.getChildren().get(1);
        root.setVBoxHandler(e->changeSceneToLoginMenu() ); // solution Code
        
        Scene scene = new Scene(root, 1280, 720);
        primaryStage.setScene(scene);
        primaryStage.show();

        this.primaryStage = primaryStage;

    }

    public void changeSceneToLoginMenu() {
        System.out.println("It finally worked");
        Scene currentScene = new Scene(new Group(),100,100); // just a demo
        primaryStage.setScene(currentScene);

    }

notes: The type of value on the method setVBoxHandler(EventHandler<? super MouseEvent> value) will depend on the setOnXXX method used. For example I tested and this soultion also works for buttons just need to change the type to EventHandler<ActionEvent> value.

Some coments on the question posted links on "how to use handlers", this posts used anomimous classes. I belived This way is outdated. I used lambdas in the code the end result is the same but more redable code

Just for reference if future readers are using anomimous classes the solution would be the same just change the way you set up the handler:


// lambdas
setVBoxHandler( e -> System.out.println("Code run if mouse is clicked "));

// anomimous classes
setVBoxHandler(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event){
        System.out.println("Code run if mouse is clicked ");
    }
});