Switching scenes don't retain maximized screen in JavaFX - java

My configuration:
I need to switch between scenes via the same stage
I need to keep a maximized stage that fills the whole screen
My issue:
although I set my stage to be maximized primaryStage.setMaximized(true);it adopts its size to the size of the scenes afterwards.
What I tried until now:
I tried using primaryStage.getScene().setRoot(<the root node of scene>). While it worked to keep the stage maximized, yet after each change of scene the focus on the previously focused gui control is lost (after switch only the first gui control in the scene hierarchy is focused). I really need scenes, so that any gui control that was focused still be will focused after the stage changes its scene.
I need your assistance:
I really need your assistance in keeping the stage maximized during changing scenes.
Here is my example code:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
// init buttons
Button btn1 = new Button("switch to next scene >>");
Button btn2 = new Button("<< switch to previous scene");
// first scene
StackPane root1 = new StackPane();
root1.getChildren().add(btn1);
Scene scene1 = new Scene(root1, 300, 250);
// second scene
StackPane root2 = new StackPane();
root2.getChildren().add(btn2);
Scene scene2 = new Scene(root2, 500, 400);
// button actions
btn1.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene2);
});
btn2.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene1);
});
primaryStage.setMaximized(true);
primaryStage.setScene(scene1);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

SOLUTION
create scenes depending on the screen size of your monitor
after several attempts I finally figured how to easily solve this problem to keep the maximized screen while retaining the focused node on each Scene. Hope it helps the community:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
// get screensize of monitor
Rectangle2D screenSize = Screen.getPrimary().getVisualBounds();
// init buttons
Button btn1 = new Button("switch to next scene >>");
Button btn2 = new Button("<< switch to previous scene");
// first rootNode
StackPane root1 = new StackPane();
root1.getChildren().add(btn1);
Scene scene1 = new Scene(root1, screenSize.getWidth(), screenSize.getHeight());
// second rootNode
StackPane root2 = new StackPane();
root2.getChildren().add(btn2);
Scene scene2 = new Scene(root2, screenSize.getWidth(), screenSize.getHeight());
// button actions
btn1.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene2);
});
btn2.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene1);
});
primaryStage.setMaximized(true); // keep this since otherwise the titlebar is bit overlapped
primaryStage.setScene(scene1);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

I think it's a bug. You can report it at: http://bugreport.java.com.
In the meantime, as a workaround, you probably need to just set the pane for a shared scene, replacing its content rather than replacing the scene.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class NewFXMainFixed extends Application {
#Override
public void start(Stage primaryStage) {
// init buttons
Button btn1 = new Button("switch to next scene >>");
Button btn2 = new Button("<< switch to previous scene");
// first scene
StackPane root1 = new StackPane();
root1.getChildren().add(btn1);
// second scene
StackPane root2 = new StackPane();
root2.getChildren().add(btn2);
// button actions
btn1.setOnAction((ActionEvent event) ->
primaryStage.getScene().setRoot(root2)
);
btn2.setOnAction((ActionEvent event) ->
primaryStage.getScene().setRoot(root1)
);
Scene scene = new Scene(root1);
primaryStage.setMaximized(true);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

Stage styling in javafx

How to apply StageStyle.utility and StageStyle.undecorated to the same stage.
I am using this for the internal window/ popup.
Or if I have to follow any other solution please do stuggest.
Thanks
Your problem :
Application two styles StageStyle.UTILITYand StageStyle.UNDECORATED for the same stage.
Because
you asked for suggestion
to solve your problem.
Suggestion :
I suggest to use in-sideFX/Undecorator
(Downlaod the jar file and add it into your project) then we will make some modifications to keep your need ,I tried to create this sample of code for creating a Popup window inside parent window (Owner window) :
package javafxpopup;
import insidefx.undecorator.Undecorator;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
/**
*
* #author Menai Ala Eddine
*/
public class Undecorated extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Click");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Stage popStage = new Stage();
popStage.initStyle(StageStyle.TRANSPARENT);
StackPane root = new StackPane();
root.getChildren().add(new Label("I'm popup window"));
applyModification(popStage, root);
popStage.show();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root,500,500));
primaryStage.setTitle("Hello World!");
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
private void applyModification(Stage primaryStage, StackPane root) {
Undecorator undecorator = new Undecorator(primaryStage, root);
undecorator.getStylesheets().add("/skin/undecorator.css");
Scene scene = new Scene(undecorator, 300, 250);
primaryStage.setScene(scene);
scene.setFill(null);
Node stageMenu = undecorator.lookup("#StageMenu");
stageMenu.setVisible(false);
Node maximize = undecorator.lookup(".decoration-button-maximize");
maximize.setVisible(false);
Node manimize = undecorator.lookup(".decoration-button-minimize");
manimize.setVisible(false);
Node restore = undecorator.lookup(".decoration-button-fullscreen");
restore.setVisible(false);
}
}
By clicking the button the pop window will showing into owner window :
As you see StageStyle.UNDECORATED and StageStyle.UTILITY in the same time.
PS: it is a suggestion you can find many solutions.

Let Window scroll down in JavaFX

So I am trying to learn Java now that I know JavaScript and PHP. I am working in Netbeans with JavaFX and I am trying to create a program that creates 5 buttons. (This is modifying the code that comes with Netbeans when creating a new JavaFX Application.) If I change the y-argument of the scene to be less than the y of all of the buttons, it will not display the remaining buttons and it will not be able scroll down. This is what I have so far. How do I enable it to scroll down so all buttons can be seen? I know that I can just change the scene back to its old height but I want to learn about scrolling with JavaFX.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javax.swing.JScrollPane;
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
Button[] btn=new Button[5];
for(int i=0;i<5;i++){
btn[i] = new Button();
btn[i].setText(i+"");
GridPane.setRowIndex(btn[i],i);
root.getChildren().addAll(btn[i]);
btn[i].setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("This is a button");
}
});
}
Scene scene = new Scene(root, 300, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Using ScrollPane to set root as:
ScrollPane sp = new ScrollPane();
sp.setContent(root);
Scene scene = new Scene(sp, 300, 50);

Application with BorderPane doesn't display simple button

very new to JavaFX I'm following a simple tutorial here
I created a new JavaFX project but it has a BorderPane as a default rather than a StackPane as the tutorial says, so I left it there.
The application only has a button on it and if I use the BorderPane the button isn't displayed.
If I change it to StackPane the button shows up.
Thinking that for some reason the BorderPane was clipping something off, I made the application windows full size, but I still couldn't see the button.
Here is the code with the BorderPane the one that doesn't display the button:
package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("This is a test!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
root.getChildren().add(btn);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Any idea?
Take a look at the docs about BorderPane:
BorderPane lays out children in top, left, right, bottom, and center
positions.
Therefore you need to use stuff like:
borderPane.setTop(toolbar);
borderPane.setCenter(appContent);
borderPane.setBottom(statusbar);
In your case root.getChildren().add(btn); should be for example root.setCenter(btn);.

how to have a scene over another in javafx

I'm writing a small game. And i want a pause menu over the blured game menu to be shown when esc is pressed in the middle of the game.
What I do is that i make a new scene which has a stackPane wrapping the past root and the pause menu root and then i set the opacity of the past root 0.4 .
Then when the resume button in the pause menu is clicked i change the opacity back to 1 and set the past scene on stage but then its freezed. does anyone know why? can anyone help me achieve this?
Here is the part i make the new scene and then i put this on stage:
StackPane wrapper = new StackPane();
previousScene = main.getPrimaryStage().getScene();
previousScene.getRoot().setOpacity(.4);
vBox.setId("pausedWrapper");
wrapper.getChildren().add(previousScene.getRoot());
wrapper.getChildren().add(vBox);
scene = new Scene(wrapper, 1200, 700);
return scene;
Here is the part i change it back to where it was:
resumeGame.setOnAction(event -> {
System.out.println("game resumed!");
previousScene.getRoot().setOpacity(1);
main.getPrimaryStage().setScene(previousScene);
});
But then it does not work and the opacity does not change back to normal and the strange thing is when i check the sound on box the music is played but the box does not get checked like everything works but the view is freezed.
A node cannot be part of two different scene graphs. This happens in your code to the root of previousScene, because it is part of both previousScene and the new scene you create in your first block of code. Most likely what is happening is that it is removed from the first scene when you add it to the second (though it is hard to tell from the code you posted).
Consider instead using a Popup to display the pauseMenu on top of the existing window, or just use a modal Stage with undecorated StageStyle, as in the following SSCCE:
import javafx.animation.Animation;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Modality;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class PauseExample extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(50, 50, 50, 50);
rect.setFill(Color.CORAL);
TranslateTransition animation = createAnimation(rect);
Button pauseButton = new Button("Pause");
Pane pane = new Pane(rect);
pane.setMinSize(600, 150);
BorderPane root = new BorderPane(pane, null, null, pauseButton, new Label("This is\nthe main\nscene"));
pauseButton.setOnAction(e -> {
animation.pause();
root.setEffect(new GaussianBlur());
VBox pauseRoot = new VBox(5);
pauseRoot.getChildren().add(new Label("Paused"));
pauseRoot.setStyle("-fx-background-color: rgba(255, 255, 255, 0.8);");
pauseRoot.setAlignment(Pos.CENTER);
pauseRoot.setPadding(new Insets(20));
Button resume = new Button("Resume");
pauseRoot.getChildren().add(resume);
Stage popupStage = new Stage(StageStyle.TRANSPARENT);
popupStage.initOwner(primaryStage);
popupStage.initModality(Modality.APPLICATION_MODAL);
popupStage.setScene(new Scene(pauseRoot, Color.TRANSPARENT));
resume.setOnAction(event -> {
root.setEffect(null);
animation.play();
popupStage.hide();
});
popupStage.show();
});
BorderPane.setAlignment(pauseButton, Pos.CENTER);
BorderPane.setMargin(pauseButton, new Insets(5));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private TranslateTransition createAnimation(Rectangle rect) {
TranslateTransition animation = new TranslateTransition(Duration.seconds(1), rect);
animation.setByX(400);
animation.setCycleCount(Animation.INDEFINITE);
animation.setAutoReverse(true);
animation.play();
return animation;
}
public static void main(String[] args) {
launch(args);
}
}

Waiting for Scene repaint

Is there any possible way to wait for the scene to repaint?
My problem is, that i want to add a Note to a Pane with getChildren().add() and then to fire an event on this Node with Node.fireEvent(event).
But the event is not performed. I think the problem is, that the scene was not repainted at the point of the fireevent and so the Node is not a part of the new Scene at this time.
So the best way would be to wait for the scene to repaint and then fire the event i think.
I do not know which is the UI Component you has been used here, but, try to find out the invalidate() method (or something like that) of your component to make it update the screen after all.
Can you post code? This works fine for me:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class NewNodeEventTest extends Application {
#Override
public void start(Stage primaryStage) {
HBox root = new HBox(5);
Button newNodeButton = new Button("Add button");
newNodeButton.setOnAction(event -> {
Button newButton = new Button("Button");
newButton.setOnAction(e -> System.out.println("New button pressed"));
root.getChildren().add(newButton);
ActionEvent evt = new ActionEvent(newButton, newButton);
newButton.fireEvent(evt);
});
root.getChildren().add(newNodeButton);
Scene scene = new Scene(root, 250, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Categories