Reputation: 13
Please help me make it works. It freezes instead of changing Scenes. It works fine when buttons are created this way:
Button b1 = new Button("Go to s2");
b1.setOnAction(e -> window.setScene(s2));
Button b2 = new Button("Go to s1");
b2.setOnAction(e -> window.setScene(s1));
But I'd like to make it more elegant...
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class Main extends Application {
Stage window;
Scene s1,s2;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
Button b1 = makeButton("Go to s2", s2);
Button b2 = makeButton("Go to s1", s1);
s1 = new Scene(b1);
s2 = new Scene(b2);
primaryStage.setScene(s1);
primaryStage.show();
}
public Button makeButton(String name, Scene destScene) {
Button button = new Button(name);
button.setOnAction(e -> window.setScene(destScene));
return button;
}
}
Thank you very much in advance!
Upvotes: 1
Views: 581
Reputation: 10613
Look at the order for how everything is initialized:
Button b1 = makeButton("Go to s2", s2);
Button b2 = makeButton("Go to s1", s1);
s1 = new Scene(b1);
s2 = new Scene(b2);
When you call makeButton
, you pass in the value of the reference currently stored in s1
and s2
. Since it was never initialized, it takes the default value of null
. This doesn't get changed when you letter set s1
and s2
because of the copied reference.
You don't have the same problem in the first case, because you never make a copy of s1
and s2
. Instead, you have the EventHandler
refer to the field in the current instance of Main
, which does get correctly updated once you set it. So your original code is something equivalent to this:
Button b1 = new Button("Go to s2");
b1.setOnAction(e -> window.setScene(this.s2));
So you're copying the reference to the enclosing Main
instance, rather than the reference to the button itself.
I don't see any trivial fix for it unfortunately. The easiest solution I see would be to change your function to makeButton(String, EventHandler<ActionEvent>)
, and call it like this:
Button b1 = makeButton("Go to s2", e -> window.setScene(s2));
Not as nice as what you want, but it should work.
Another possible solution is to put all of your Button
s into an array, and then pass an index into that array into makeButton
. That would look like tihs:
public class Main extends Application {
Stage window;
Scene[] scenes = new Scene[2];
@Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
Button b1 = makeButton("Go to s2", 1);
Button b2 = makeButton("Go to s1", 0);
scenes[0] = new Scene(b1);
scenes[1] = new Scene(b2);
primaryStage.setScene(scenes[0]);
primaryStage.show();
}
public Button makeButton(String name, int destScene) {
Button button = new Button(name);
button.setOnAction(e -> window.setScene(scenes[destScene]));
return button;
}
}
That changes the EventHandler
to reference a field of Main
(scenes
) rather than a local variable (destScene
).
Upvotes: 1