Q: Confused about switching screens JavaFX - javafx

I dont understand how to switch between the current screen and the register screen:
package Computing;
import javafx.scene.layout.*;import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javafx.stage.Window;
public class Computing extends Application {
Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
primaryStage.setTitle("Computing Quiz");
GridPane gridPane = createComputingQuizPane();
// ui controls to gridpane
addUIControls(gridPane);
// scene
Scene scene = new Scene(gridPane, 800, 500);
// primary stage scene set
primaryStage.setScene(scene);
primaryStage.show();
}
private GridPane createComputingQuizPane() {
// Instantiate a new Grid Pane
GridPane gridPane = new GridPane();
gridPane.setAlignment(Pos.CENTER);
gridPane.setPadding(new Insets(40, 40, 40, 40));
gridPane.setHgap(10);
gridPane.setVgap(10);
return gridPane;
}
private void addUIControls(GridPane gridPane) {
// HEADER
Label headerLabel = new Label("Welcome to the Computing Quiz!");
headerLabel.setFont(Font.font("Arial", FontWeight.BOLD, 24));
gridPane.add(headerLabel, 0,0,2,1);
GridPane.setHalignment(headerLabel, HPos.CENTER);
GridPane.setMargin(headerLabel, new Insets(20, 0,20,0));
// LOGIN BUTTON
Button loginButton = new Button("Login");
loginButton.setPrefHeight(50);
loginButton.setDefaultButton(true);
loginButton.setPrefWidth(125);
gridPane.add(loginButton, 0, 4, 2, 1);
GridPane.setHalignment(loginButton, HPos.CENTER);
GridPane.setMargin(loginButton, new Insets(20, 0,20,0));
// REGISTER BUTTON
Button registerButton = new Button ("Register");
registerButton.setOnAction(e-> buttonClick());
registerButton.setPrefHeight(50);
registerButton.setDefaultButton(true);
registerButton.setPrefWidth(125);
gridPane.add(registerButton,0,5,2,1);
GridPane.setHalignment(registerButton,HPos.CENTER);
GridPane.setMargin(registerButton, new Insets(20,0,20,0));
//registerButton.setOnAction(new EventHandler<ActionEvent>() {
//#Override
//public void handle(ActionEvent event) {
//Register nc = new Register(stage);
//}
//});
}
public void buttonClick(){
Register nc = new Register(stage);
}
public static void main(String[] args) {
launch(args);
}
}
This is the register screen:
package Computing;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javafx.stage.Window;
public class Register {
Stage stage;
public Register (Stage s){
stage = s;
}
public void start(Stage primaryStage){
primaryStage.setTitle("Registration");
GridPane gridPane = createRegisterPane();
addUIControls(gridPane);
Scene scene = new Scene(gridPane, 800, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
private GridPane createRegisterPane() {
GridPane gridPane = new GridPane();
gridPane.setAlignment(Pos.CENTER);
gridPane.setPadding(new Insets(40, 40, 40, 40));
gridPane.setHgap(10);
gridPane.setVgap(10);
return gridPane;
}
private void addUIControls(GridPane gridPane) {
// Add Header
Label headerLabel = new Label("Registration Form");
headerLabel.setFont(Font.font("Arial", FontWeight.BOLD, 24));
gridPane.add(headerLabel, 0,0,2,1);
GridPane.setHalignment(headerLabel, HPos.CENTER);
GridPane.setMargin(headerLabel, new Insets(20, 0,20,0));
// FULL NAME
Label nameLabel = new Label("Full Name : ");
gridPane.add(nameLabel, 0,1);
// FULL NAME TEXT
TextField nameField = new TextField();
nameField.setPrefHeight(40);
gridPane.add(nameField, 1,1);
// USERNAME
Label emailLabel = new Label("Username : ");
gridPane.add(emailLabel, 0, 2);
// EMAIL TEXT
TextField emailField = new TextField();
emailField.setPrefHeight(40);
gridPane.add(emailField, 1, 2);
// PASSWORD
Label passwordLabel = new Label("Password : ");
gridPane.add(passwordLabel, 0, 3);
// PASSWORD TEXT
PasswordField passwordField = new PasswordField();
passwordField.setPrefHeight(40);
gridPane.add(passwordField, 1, 3);
// SUBMIT BUTTON
Button submitButton = new Button("Submit");
submitButton.setPrefHeight(40);
submitButton.setDefaultButton(true);
submitButton.setPrefWidth(100);
gridPane.add(submitButton, 0, 4, 2, 1);
GridPane.setHalignment(submitButton, HPos.CENTER);
GridPane.setMargin(submitButton, new Insets(20, 0,20,0));
submitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if(nameField.getText().isEmpty()) {
showAlert(Alert.AlertType.ERROR, gridPane.getScene().getWindow(), "Error", "Please enter your name.");
return;
}
if(emailField.getText().isEmpty()) {
showAlert(Alert.AlertType.ERROR, gridPane.getScene().getWindow(), "Error", "Please enter a Username");
return;
}
if(passwordField.getText().isEmpty()) {
showAlert(Alert.AlertType.ERROR, gridPane.getScene().getWindow(), "Error!", "Please enter a password");
return;
}
showAlert(Alert.AlertType.CONFIRMATION, gridPane.getScene().getWindow(), "Registration Successful!", "Welcome " + nameField.getText());
}
});
}
private void showAlert(Alert.AlertType alertType, Window owner, String title, String message) {
Alert alert = new Alert(alertType);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
alert.initOwner(owner);
alert.show();
}
public static void main(String[] args) {
launch(args);
}
}
I've tried using this instead of the buttonClick method also I'm slightly confused as to why it won't work as before I used the same method using buttonClick to send the scene to the next screen
submitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {

Related

javafx programs for user validation. Add user program works great. Login program has runtime errors. Tried many solutions, need assistance please

Having problems getting the "Login" program to run properly. AddUser works great, Login does not and ends up not responding. I have tried many code changes to "Login" and feel I nearly had it but the best I got was the GUI to display the "Invalid Username or Password" error although both were proper. Need HELP please!!
Here is the code for AddUser.java which writes the selected username and password to a users.txt file:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.io.*;
public class AddUser extends Application {
private TextField tfUsername = new TextField();
private TextField tfPassword = new TextField();
private Button btAddUser = new Button("Add User");
private Button btClear = new Button("Clear");
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create UI
GridPane gridPane = new GridPane();
gridPane.setHgap(5);
gridPane.setVgap(5);
gridPane.add(new Label("Username:"), 0, 0);
gridPane.add(tfUsername, 1, 0);
gridPane.add(new Label("Password:"), 0, 1);
gridPane.add(tfPassword, 1, 1);
gridPane.add(btAddUser, 1, 3);
gridPane.add(btClear, 1, 3);
// Set properties for UI
gridPane.setAlignment(Pos.CENTER);
tfUsername.setAlignment(Pos.BOTTOM_LEFT);
tfPassword.setAlignment(Pos.BOTTOM_LEFT);
GridPane.setHalignment(btAddUser, HPos.RIGHT);
GridPane.setHalignment(btClear, HPos.LEFT);
Text text = new Text(" ");
text.setFont(Font.font("Copperplate Gothic Light", FontWeight.SEMI_BOLD, FontPosture.REGULAR, 16));
text.setFill(Color.BLUE);
// Process events
btAddUser.setOnAction(e -> {
writeNewUser();
text.setText("User " + tfUsername.getText()+ " Added!");
});
btClear.setOnAction(e -> {
tfUsername.clear();
tfPassword.clear();
text.setText(" ");
});
VBox vbox = new VBox(2);
vbox.getChildren().addAll(text, gridPane);
// Create a scene and place it in the stage
Scene scene = new Scene(vbox, 300, 150);
primaryStage.setTitle("Add User"); // Set title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public void writeNewUser() {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("users.txt", true))) {
bw.write(tfUsername.getText()+"|"+tfPassword.getText());
bw.newLine();
}
catch (IOException e){
e.printStackTrace();
}
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
Now, here is the "Login" program's code, this is where I'm having trouble.
import java.io.*;
import java.util.*;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Login extends Application {
private TextField tfUser = new TextField();
private PasswordField tfPass = new PasswordField();
private Button btLogin = new Button("Login");
private Button btClear = new Button("Clear");
#SuppressWarnings("resource")
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create UI
GridPane gridPane = new GridPane();
gridPane.setHgap(5);
gridPane.setVgap(5);
gridPane.add(new Label("Username:"), 0, 0);
gridPane.add(tfUser, 1, 0);
gridPane.add(new Label("Password:"), 0, 1);
gridPane.add(tfPass, 1, 1);
gridPane.add(btLogin, 1, 3);
gridPane.add(btClear, 1, 3);
// Set properties for UI
gridPane.setAlignment(Pos.CENTER);
tfUser.setAlignment(Pos.BOTTOM_LEFT);
tfPass.setAlignment(Pos.BOTTOM_LEFT);
GridPane.setHalignment(btLogin, HPos.RIGHT);
GridPane.setHalignment(btClear, HPos.LEFT);
Text text = new Text();
text.setFont(Font.font("Copperplate Gothic Light", FontWeight.SEMI_BOLD, FontPosture.REGULAR, 16));
// Process events
btClear.setOnAction(e ->
{
tfUser.clear();
tfPass.clear();
text.setText("");
});
btLogin.setOnAction(e -> {
boolean grantAccess = false;
String userName = tfUser.getText();
String password = tfPass.getText();
File f = new File("users.txt");
try {
Scanner read = new Scanner(f);
int noOfLines=0;
while(read.hasNextLine()) {
noOfLines++;
}
for(int i=0; i<noOfLines; i++) {
if (read.nextLine().equals(userName)) {
i++;
if (read.nextLine().equals(password)) {
grantAccess=true;
break;
}
}
}
if(grantAccess) {
text.setText("Welcome!");
text.setFill(Color.BLUEVIOLET);
}
else {text.setText("Invalid Username or Password!");
text.setFill(Color.RED);
}
}
catch(FileNotFoundException e1) {
e1.printStackTrace();
}
});
VBox vbox = new VBox(2);
vbox.getChildren().addAll(text, gridPane);
// Create a scene and place it in the stage
Scene scene = new Scene(vbox, 300, 150);
primaryStage.setTitle("LOGIN"); // Set title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
Any Help Is Greatly Appreciated!!!! Thank you!

How to set popup scene mouse transparent in javafx

How to do that in JavaFX?
The popup shows up when the mouse enters a node. When the mouse enters the showing popup, the popup obscures the mouse from the node. Then the node fire exit event. How to make the popup ignore the mouse events?
code
package sample;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
primaryStage.setScene(new Scene(root, 300, 275));
Label labelNode = new Label("Label Node");
labelNode.setPrefHeight(200);
labelNode.styleProperty().set("-fx-background-color: orange");
Popup popup = new Popup();
popup.getScene().getRoot().setMouseTransparent(true);
AnchorPane popContent =new AnchorPane();
popContent.styleProperty().set("-fx-background-color: red");
popContent.setPrefHeight(100);
popContent.getChildren().add(new Label("Popup content"));
popup.getContent().add(popContent);
labelNode.setOnMouseEntered(event->{
Point3D point3D = labelNode.localToScene(event.getX(), event.getY(), 0);
popup.show(primaryStage, point3D.getX()-5, point3D.getY()-5);
});
labelNode.setOnMouseExited(event->{
popup.hide();
});
root.getChildren().add(labelNode);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Please try moving the cursor in to "yellow" several times.
Solution:
Keep two boolean nodeExited and popupExited statuses. Hide popup when both are true.
package sample;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class Main extends Application {
boolean nodeExited = false;
boolean popupExited = false;
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
primaryStage.setScene(new Scene(root, 300, 275));
Label labelNode = new Label("Label Node");
labelNode.setPrefHeight(200);
labelNode.styleProperty().set("-fx-background-color: orange");
Popup popup = new Popup();
popup.getScene().getRoot().setMouseTransparent(true);
AnchorPane popContent = new AnchorPane();
popContent.styleProperty().set("-fx-background-color: red");
popContent.setPrefHeight(100);
popContent.getChildren().add(new Label("Popup content"));
popup.getContent().add(popContent);
popup.getScene().setOnMouseEntered(event -> {
popupExited = false;
});
popup.getScene().setOnMouseExited(event -> {
popupExited = true;
if (nodeExited)
popup.hide();
});
labelNode.setOnMouseEntered(event -> {
nodeExited = false;
Point3D point3D = labelNode.localToScene(event.getX(), event.getY(), 0);
popup.show(primaryStage, point3D.getX() - 5, point3D.getY() - 5);
});
labelNode.setOnMouseExited(event -> {
nodeExited = true;
if (popupExited)
popup.hide();
});
root.getChildren().add(labelNode);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

changing my textfield to upper/lower case is not working as intended

After creating my GUI my next step was to have the buttons be able to change the textfield to their respective case when pressed. However none of the ways I have tried seem to demonstrate that.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class UpperLowerClass extends Application {
private Button upperButton;
private Button lowerButton;
private String userText;
private TextField userInput;
private Stage window;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
window = primaryStage;
window.setTitle("Uppercase to Lowercase");
//GRID
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 10, 10, 10));
grid.setVgap(10);
grid.setHgap(10);
//UPPERCASE BUTTON
upperButton = new Button("Uppercase");
upperButton.setOnAction(this::changeTextButton);
GridPane.setConstraints(upperButton, 0, 0);
//LOWERCASE BUTTON
lowerButton = new Button("Lowercase");
lowerButton.setOnAction(this::changeTextButton);
GridPane.setConstraints(lowerButton, 0, 1);
//TEXTFIELD
TextField userInput = new TextField();
userInput.getText();
userInput.setText(String.valueOf(userText));
GridPane.setConstraints(userInput, 0, 2);
grid.getChildren().addAll(upperButton, lowerButton, userInput);
//SCENE
Scene myScene = new Scene(grid, 300, 250);
window.setScene(myScene);
window.show();
primaryStage.setScene(myScene);
primaryStage.show();
}
//EVENT
public void changeTextButton(ActionEvent event)
{
if (event.getSource() ==upperButton) {
userText = userText.toUpperCase();
}
if (event.getSource() ==lowerButton) {
userInput.setText(String.valueOf(userText.toLowerCase()));
}
}
}
There must be a problem with how I am retrieving the text or is it entirely because of the manipulation I am trying to do in the If statements? Each button is the two versions I have tried which leads me to think that I am retrieving the text wrong or manipulating wrong. Thank you in advance!
Is the String userText needed elsewhere? Getting and setting the text of userInput directly through getText() and setText() would be better imo. Additionally, there is no need to create a local variable for userInput when you have it as a global variable already.
This is your code tested working: (I removed the changeTextButton method and just made the changes from the buttons directly, but this could be split out easily enough.)
public class UpperLowerClass extends Application {
private Button upperButton;
private Button lowerButton;
private TextField userInput;
private Stage window;
#Override
public void start(Stage primaryStage) {
try {
window = primaryStage;
//GRID
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 10, 10, 10));
grid.setVgap(10);
grid.setHgap(10);
//UPPERCASE BUTTON
upperButton = new Button("Uppercase");
upperButton.setOnAction(event -> {
if(userInput.getText()!=null) {
userInput.setText(userInput.getText().toUpperCase());
}
});
// upperButton.setOnAction(this::changeTextButton);
GridPane.setConstraints(upperButton, 0, 0);
//LOWERCASE BUTTON
lowerButton = new Button("Lowercase");
//lowerButton.setOnAction(this::changeTextButton);
lowerButton.setOnAction(event -> {
if(userInput.getText()!=null) {
userInput.setText(userInput.getText().toLowerCase());
}
});
GridPane.setConstraints(lowerButton, 0, 1);
//TEXTFIELD
userInput = new TextField(); //don't need to create new Textfield here
GridPane.setConstraints(userInput, 0, 2);
grid.getChildren().addAll(upperButton, lowerButton, userInput);
//SCENE
Scene myScene = new Scene(grid, 300, 250);
window.setScene(myScene);
window.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

How to control the overlapping expansion of a JavaFX titledpane

Would anyone know how to configure a JavaFX titledPane in such a way that the expansion always takes place in the foreground? As is the case with the expansion of a ComboBox button.
When the region of the panel containing the titledPane is smaller than the expansion region, the expansion occurs behind the invaded area. How to do that in front of the invaded region.
The sample code shows this scenario. The functionality I wish could be implemented with the use of a comboBox button containing buttons, but I like the effect created in the titledPane expansion and would like to use it alternately.
Thank you in advance.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
TitledPane titledPane = new TitledPane();
titledPane.setPrefWidth(180);
titledPane.setBorder(new Border(new BorderStroke(Color.MAGENTA, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(1))));
Button btnSave = new Button();
btnSave.setPrefWidth(180);
btnSave.setText("Save");
btnSave.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(false);
}
});
Button btnLeftSend = new Button();
btnLeftSend.setPrefWidth(180);
btnLeftSend.setText("Sent to Left");
btnLeftSend.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(false);
}
});
Button btnRightSend = new Button();
btnRightSend.setPrefWidth(180);
btnRightSend.setText("Sent to right");
btnRightSend.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(false);
}
});
VBox buttons = new VBox(3);
buttons.setPrefWidth(180);
buttons.getChildren().addAll(btnSave, btnLeftSend, btnRightSend);
titledPane.setAnimated(true);
titledPane.setText("Options");
titledPane.setContent(buttons);
titledPane.setExpanded(false);
Button btnLine1 = new Button();
btnLine1.setPrefWidth(180);
btnLine1.setText("Force expand");
btnLine1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(true);
}
});
HBox line1 = new HBox(5);
line1.setPadding(new Insets(5, 0, 0, 0));
line1.setAlignment(Pos.TOP_CENTER);
line1.setMaxSize(380, 40);
line1.setMinSize(380, 40);
line1.setPrefSize(380, 40);
line1.setBorder(new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(1))));
line1.getChildren().addAll(btnLine1, titledPane);
Button btnLine2 = new Button();
btnLine2.setPrefWidth(180);
btnLine2.setText("Force shrink");
btnLine2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(false);
}
});
HBox line2 = new HBox(5);
line2.setPadding(new Insets(5, 0, 0, 0));
line2.setAlignment(Pos.TOP_CENTER);
line2.setMaxSize(380, 40);
line2.setMinSize(380, 40);
line2.setPrefSize(380, 40);
line2.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(1))));
line2.getChildren().add(btnLine2);
VBox layout = new VBox(5);
layout.setPadding(new Insets(5));
layout.getChildren().addAll(line1, line2);
Scene scene = new Scene(layout, 390, 160);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
scene.setFill(Color.GHOSTWHITE);
primaryStage.setTitle("Sample code for StackOverFlow");
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
The z-order of nodes is controlled by the order in which they are added to their parent. If you use a VBox, of course, this order also determines the position of the node within the VBox. Consider instead using, for example, a grid pane, so you can control the position independently of the order in which the child nodes are added. Then just add line1 after adding line2:
// VBox layout = new VBox(5);
// layout.setPadding(new Insets(5));
// layout.getChildren().addAll(line1, line2);
GridPane layout = new GridPane();
layout.setVgap(5);
layout.setPadding(new Insets(5));
layout.add(line2, 0, 1);
layout.add(line1, 0, 0);
Many thanks for the reply. I replaced the VBox with GridPane in my application and it worked as I wanted it to.
For the purpose of helping other people with the same problem, follow the modified code at the suggestion of James_D.
package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
TitledPane titledPane = new TitledPane();
titledPane.setPrefWidth(180);
Button btnSave = new Button();
btnSave.setPrefWidth(180);
btnSave.setText("Save");
btnSave.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(false);
}
});
Button btnLeftSend = new Button();
btnLeftSend.setPrefWidth(180);
btnLeftSend.setText("Sent to Left");
btnLeftSend.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(false);
}
});
Button btnRightSend = new Button();
btnRightSend.setPrefWidth(180);
btnRightSend.setText("Sent to right");
btnRightSend.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(false);
}
});
VBox buttons = new VBox(3);
buttons.setPrefWidth(180);
buttons.getChildren().addAll(btnSave, btnLeftSend, btnRightSend);
titledPane.setAnimated(true);
titledPane.setText("Options");
titledPane.setContent(buttons);
titledPane.setExpanded(false);
Button btnLine1 = new Button();
btnLine1.setPrefWidth(180);
btnLine1.setText("Force expand");
btnLine1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
titledPane.setExpanded(true);
}
});
HBox line1 = new HBox(5);
line1.setPadding(new Insets(5, 0, 0, 0));
line1.setAlignment(Pos.TOP_CENTER);
line1.setMaxSize(380, 40);
line1.setMinSize(380, 40);
line1.setPrefSize(380, 40);
line1.getChildren().addAll(btnLine1, titledPane);
Button btnDummy = new Button();
btnDummy.setPrefWidth(365);
btnDummy.setText("Anything here. Just an example");
HBox line2 = new HBox(5);
line2.setPadding(new Insets(5, 0, 0, 0));
line2.setAlignment(Pos.TOP_CENTER);
line2.setMaxSize(380, 40);
line2.setMinSize(380, 40);
line2.setPrefSize(380, 40);
line2.getChildren().add(btnDummy);
GridPane layout = new GridPane();
layout.setVgap(5);
layout.setPadding(new Insets(5));
layout.add(line2, 0, 1);
layout.add(line1, 0, 0);
Scene scene = new Scene(layout, 390, 160);
primaryStage.setTitle("Sample code for StackOverFlow");
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX position dialog and stage in center of screen

The following codes demonstrates centering of a dialog and the stage in the center of the screen. The dialog is supposed to be displayed first for the user to enter the login credentials. After successful login, the main window (stage) is then displayed. I found the solution of centering the dialog and stage from this web site, but it doesn't seem very ideal. For both the dialog and stage, they have to be displayed first before we can calculate the coordinates and then positioning them in the center. This means that we can see the dialog and the main window moving to the center after they are displayed. Is there a better way? Ideally, they should be positioned in the center before they are displayed.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.Window;
public class Demo extends Application {
private Stage primaryStage;
private Dialog<String> dialog;
private Button createUserButton = new Button("Create User");
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
Text usersLabel = new Text("Current Users:");
TableColumn<User, String> indexColumn = new TableColumn<User, String>("No.");
indexColumn.setMaxWidth(1f * Integer.MAX_VALUE * 10);
indexColumn.setCellValueFactory(p -> p.getValue().indexProperty());
TableColumn<User, String> userNameColumn = new TableColumn<User, String>("User Name");
userNameColumn.setMaxWidth(1f * Integer.MAX_VALUE * 60);
userNameColumn.setCellValueFactory(p -> p.getValue().userNameProperty());
TableColumn<User, String> roleColumn = new TableColumn<User, String>("Role");
roleColumn.setMaxWidth(1f * Integer.MAX_VALUE * 30);
roleColumn.setCellValueFactory(p -> p.getValue().roleProperty());
TableView<User> tableView = new TableView<User>();
tableView.getColumns().add(indexColumn);
tableView.getColumns().add(userNameColumn);
tableView.getColumns().add(roleColumn);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
Text dummyLabel = new Text("");
VBox leftPane = new VBox(5);
leftPane.getChildren().addAll(usersLabel, tableView);
VBox rightPane = new VBox(20);
rightPane.setFillWidth(true);
rightPane.getChildren().addAll(dummyLabel, createUserButton);
GridPane mainPane = new GridPane();
mainPane.setPadding(new Insets(10, 0, 0, 10));
mainPane.setHgap(20);
mainPane.add(leftPane, 0, 0);
mainPane.add(rightPane, 1, 0);
Scene scene = new Scene(mainPane);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
showDialog();
}
private void showDialog() {
dialog = new Dialog<>();
dialog.setTitle("Login");
dialog.setHeaderText("Please enter User Name and Password to login.");
dialog.setResizable(false);
Label userNameLabel = new Label("User Name:");
Label passwordLabel = new Label("Password:");
TextField userNameField = new TextField();
PasswordField passwordField = new PasswordField();
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(20, 35, 20, 35));
grid.add(userNameLabel, 1, 1);
grid.add(userNameField, 2, 1);
grid.add(passwordLabel, 1, 2);
grid.add(passwordField, 2, 2);
dialog.getDialogPane().setContent(grid);
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
Button okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
okButton.addEventFilter(ActionEvent.ACTION, event -> {
createUser(userNameField.getText().trim(), passwordField.getText());
event.consume();
});
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Platform.runLater(() -> {
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
Window window = dialog.getDialogPane().getScene().getWindow();
window.setX((screenBounds.getWidth() - window.getWidth()) / 2);
window.setY((screenBounds.getHeight() - window.getHeight()) / 2);
});
dialog.showAndWait();
}
private void createUser(String userName, String password) {
dialog.getDialogPane().setDisable(true);
dialog.getDialogPane().getScene().setCursor(Cursor.WAIT);
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() {
try {
Thread.sleep(100);
} catch (InterruptedException exception) {
}
return Boolean.TRUE;
}
};
task.setOnSucceeded(e -> {
Boolean success = task.getValue();
dialog.getDialogPane().setDisable(false);
dialog.getDialogPane().getScene().setCursor(Cursor.DEFAULT);
if (success.booleanValue()) {
Platform.runLater(() -> {
dialog.close();
primaryStage.show();
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
primaryStage.setX((screenBounds.getWidth() - primaryStage.getWidth()) / 2);
primaryStage.setY((screenBounds.getHeight() - primaryStage.getHeight()) / 2);
});
} else {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Login Error");
alert.setHeaderText("Unable to login.");
alert.showAndWait();
}
});
new Thread(task).start();
}
public static void main(String[] arguments) {
Application.launch(arguments);
}
}
class User {
private StringProperty index;
private StringProperty userName;
private StringProperty role;
public String getIndex() {
return indexProperty().get();
}
public StringProperty indexProperty() {
if (index == null) {
index = new SimpleStringProperty(this, "index");
}
return index;
}
public void setIndex(String index) {
indexProperty().set(index);
}
public String getUserName() {
return userNameProperty().get();
}
public StringProperty userNameProperty() {
if (userName == null) {
userName = new SimpleStringProperty(this, "userName");
}
return userName;
}
public void setUserName(String userName) {
userNameProperty().set(userName);
}
public String getRole() {
return roleProperty().get();
}
public StringProperty roleProperty() {
if (role == null) {
role = new SimpleStringProperty(this, "role");
}
return role;
}
public void setRole(String role) {
roleProperty().set(role);
}
}
Below is solution by setting custom dimensions to stage and dialog. It works for the stage but it doesn't work for the dialog.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.stage.WindowEvent;
public class Demo extends Application {
private Stage primaryStage;
private Dialog<String> dialog;
private Button createUserButton = new Button("Create User");
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
Text usersLabel = new Text("Current Users:");
TableColumn<User, String> indexColumn = new TableColumn<User, String>("No.");
indexColumn.setMaxWidth(1f * Integer.MAX_VALUE * 10);
indexColumn.setCellValueFactory(p -> p.getValue().indexProperty());
TableColumn<User, String> userNameColumn = new TableColumn<User, String>("User Name");
userNameColumn.setMaxWidth(1f * Integer.MAX_VALUE * 60);
userNameColumn.setCellValueFactory(p -> p.getValue().userNameProperty());
TableColumn<User, String> roleColumn = new TableColumn<User, String>("Role");
roleColumn.setMaxWidth(1f * Integer.MAX_VALUE * 30);
roleColumn.setCellValueFactory(p -> p.getValue().roleProperty());
TableView<User> tableView = new TableView<User>();
tableView.getColumns().add(indexColumn);
tableView.getColumns().add(userNameColumn);
tableView.getColumns().add(roleColumn);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
Text dummyLabel = new Text("");
VBox leftPane = new VBox(5);
leftPane.getChildren().addAll(usersLabel, tableView);
VBox rightPane = new VBox(20);
rightPane.setFillWidth(true);
rightPane.getChildren().addAll(dummyLabel, createUserButton);
GridPane mainPane = new GridPane();
mainPane.setPadding(new Insets(10, 0, 0, 10));
mainPane.setHgap(20);
mainPane.add(leftPane, 0, 0);
mainPane.add(rightPane, 1, 0);
float width = 372f;
float height = 470f;
Scene scene = new Scene(mainPane, width, height);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
primaryStage.setX((screenBounds.getWidth() - width) / 2);
primaryStage.setY((screenBounds.getHeight() - height) / 2);
showDialog();
}
private void showDialog() {
dialog = new Dialog<>();
dialog.setTitle("Login");
dialog.setHeaderText("Please enter User Name and Password to login.");
dialog.setResizable(false);
Label userNameLabel = new Label("User Name:");
Label passwordLabel = new Label("Password:");
TextField userNameField = new TextField();
PasswordField passwordField = new PasswordField();
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(20, 35, 20, 35));
grid.add(userNameLabel, 1, 1);
grid.add(userNameField, 2, 1);
grid.add(passwordLabel, 1, 2);
grid.add(passwordField, 2, 2);
dialog.getDialogPane().setContent(grid);
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
Button okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
okButton.addEventFilter(ActionEvent.ACTION, event -> {
login(userNameField.getText().trim(), passwordField.getText());
event.consume();
});
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
float width = 509f;
float height = 168f;
dialog.setWidth(width);
dialog.setHeight(height);
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
dialog.setX((screenBounds.getWidth() - width) / 2);
dialog.setY((screenBounds.getHeight() - height) / 2);
dialog.showAndWait();
}
private void login(String userName, String password) {
dialog.getDialogPane().setDisable(true);
dialog.getDialogPane().getScene().setCursor(Cursor.WAIT);
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() {
try {
Thread.sleep(100);
} catch (InterruptedException exception) {
}
return Boolean.TRUE;
}
};
task.setOnSucceeded(e -> {
Boolean success = task.getValue();
dialog.getDialogPane().setDisable(false);
dialog.getDialogPane().getScene().setCursor(Cursor.DEFAULT);
if (success.booleanValue()) {
Platform.runLater(() -> {
primaryStage.show();
});
} else {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Login Error");
alert.setHeaderText("Unable to login.");
alert.showAndWait();
}
});
new Thread(task).start();
}
public static void main(String[] arguments) {
Application.launch(arguments);
}
}
class User {
private StringProperty index;
private StringProperty userName;
private StringProperty role;
public String getIndex() {
return indexProperty().get();
}
public StringProperty indexProperty() {
if (index == null) {
index = new SimpleStringProperty(this, "index");
}
return index;
}
public void setIndex(String index) {
indexProperty().set(index);
}
public String getUserName() {
return userNameProperty().get();
}
public StringProperty userNameProperty() {
if (userName == null) {
userName = new SimpleStringProperty(this, "userName");
}
return userName;
}
public void setUserName(String userName) {
userNameProperty().set(userName);
}
public String getRole() {
return roleProperty().get();
}
public StringProperty roleProperty() {
if (role == null) {
role = new SimpleStringProperty(this, "role");
}
return role;
}
public void setRole(String role) {
roleProperty().set(role);
}
}
JKostikiadis's solution:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class TestApp extends Application {
private static final double WIDTH = 316.0;
private static final double HEIGHT = 339.0;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
HBox pane = new HBox();
pane.setAlignment(Pos.CENTER);
Button b = new Button("click me");
b.setOnAction(e -> {
showDialog();
});
pane.getChildren().add(b);
Scene scene = new Scene(pane, 300, 300);
stage.setScene(scene);
centerStage(stage, WIDTH, HEIGHT);
stage.show();
}
private void showDialog() {
Alert dialog = new Alert(AlertType.ERROR);
dialog.setTitle("Error Dialog");
dialog.setHeaderText("Look, an Error Dialog");
dialog.setContentText("Ooops, there was an error!\nOoops, there was an error!");
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
centerStage(stage, -10000, -10000);
dialog.show();
System.out.println(stage.getWidth() + " " + stage.getHeight());
dialog.hide();
centerStage(stage, stage.getWidth(), stage.getHeight());
dialog.showAndWait();
}
private void centerStage(Stage stage, double width, double height) {
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
stage.setX((screenBounds.getWidth() - width) / 2);
stage.setY((screenBounds.getHeight() - height) / 2);
}
}
Unfortunately, you have to wait for the width/height of the Window (or Dialog) to be computed as well as for the Window to be shown. Since the Window is visible you will always notice the window moving when updating the xy-position.
Doing the update when the WindowEvent.WINDOW_SHOWN event is fired might provide a better result:
final Window window = dialog.getDialogPane().getScene().getWindow();
window.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
window.setX((screenBounds.getWidth() - window.getWidth()) / 2);
window.setY((screenBounds.getHeight() - window.getHeight()) / 2);
}
});
And for the primaryStage
primaryStage.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
primaryStage.setX((screenBounds.getWidth() - primaryStage.getWidth()) / 2);
primaryStage.setY((screenBounds.getHeight() - primaryStage.getHeight()) / 2);
}
});
primaryStage.show();
But as mentioned by JKostikiadis, a better and proper solution might be to compute your own dimension with respect to the current screen size.
Here is the small improvement I can see.
When running your demo on my machine, the movement is erratic:
I can see a small improvement when using WindowEvent.WINDOW_SHOWN (without usingPlatform.runLater for the first Dialog):
Anyway, I don't think using Platform.runLater for displaying the first window is ideal as there is no guarantee that showAndWait() will always be executed before the Runnable
You can center a stage on another stage before rendering it by applying the css which will provide you with the width/height.
For example.
From where you create the stage:
WindowHelper.centerChildWindowOnStage(stage, primaryStage); //assuming primary is the stage you want to center on
stage.show();
below is the code to center the unshown window (assume this is on a WindowHelper class to be reused in the app).
public static void centerChildWindowOnStage(Stage stage, Stage primaryStage ) {
if(primaryStage == null){
return;
}
double x = stage.getX();
double y = stage.getY();
// Firstly we need to force CSS and layout to happen, as the dialogPane
// may not have been shown yet (so it has no dimensions)
stage.getScene().getRoot().applyCss();
stage.getScene().getRoot().layout();
final Scene ownerScene = primaryStage.getScene();
final double titleBarHeight = ownerScene.getY();
// because Stage does not seem to centre itself over its owner, we
// do it here.
// then we can get the dimensions and position the dialog appropriately.
final double dialogWidth = stage.getScene().getRoot().prefWidth(-1);
final double dialogHeight = stage.getScene().getRoot().prefHeight(dialogWidth);
final double ownerWidth = primaryStage.getScene().getRoot().prefWidth(-1);
final double ownerHeight = primaryStage.getScene().getRoot().prefHeight(ownerWidth);
if(dialogWidth < ownerWidth){
x = primaryStage.getX() + (ownerScene.getWidth() / 2.0) - (dialogWidth / 2.0);
}else {
x = primaryStage.getX();
stage.setWidth(dialogWidth);
}
if(dialogHeight < ownerHeight){
y = primaryStage.getY() + titleBarHeight / 2.0 + (ownerScene.getHeight() / 2.0) - (dialogHeight / 2.0);
}else {
y = primaryStage.getY();
}
stage.setX(x);
stage.setY(y);
}
Well because you ask me in the commends I am going to provide an example of setting the Stage ( main application or dialog ) to the center of the screen by early initialization of their dimensions.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class TestApp extends Application {
private static final double WIDTH = 316.0;
private static final double HEIGHT = 339.0;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
HBox pane = new HBox();
pane.setAlignment(Pos.CENTER);
Button b = new Button("click me");
b.setOnAction(e -> {
showDialog();
});
pane.getChildren().add(b);
Scene scene = new Scene(pane, 300, 300);
stage.setScene(scene);
centerStage(stage, WIDTH, HEIGHT);
stage.show();
System.out.println(stage.getWidth() + " " + stage.getHeight());
}
private void showDialog() {
Alert dialog = new Alert(AlertType.ERROR);
dialog.setTitle("Error Dialog");
dialog.setHeaderText("Look, an Error Dialog");
dialog.setContentText("Ooops, there was an error!");
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
centerStage(stage, 366, 175);
dialog.showAndWait();
}
private void centerStage(Stage stage, double width, double height) {
Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
stage.setX((screenBounds.getWidth() - width) / 2);
stage.setY((screenBounds.getHeight() - height) / 2);
}
}
In the example above you will see that I have specify the application dimensions to 300,300 but I am using for width = 316.0 and height = 339.0 and you might wondering why. It's because the stage size will always be a little bigger than the Scene ( borders + Title bar etc ) so in order to find the real width and height of the Stage you will have to print the dimensions of the stage after you show it. The same logic is happening to the Dialog.
Important : Of course you could forget all about the above and just do :
stage.setWidth(300); // or a variable here
stage.setHeight(300);
But this will affect your internal components cause if previously the scene's components had a size of 300,300 now they are going to be squeezed to something less in order to make the stage to fix the size of 300,300 so in that case yes it might affect the way your application looks like.
In the past I was searching for a way to find the dimension of a label before I show it. I found out that it was possible to get it's dimensions by adding it to the Scene and then call
labe.impl_processCSS(true);
System.out.println(labe.prefWidth(-1) + "/" + labe.prefHeight(-1));
Now If I try to do the same for the main pane in the above application it shows 59/25 which are the dimensions of the button itself so this approach is not going to work in case of someone wondering about it.
Edit :
I don't really want to show this "hack" cause I find it stupid and i am sure there is a better way, but until I find it here you go :
private void showDialog() {
Alert dialog = new Alert(AlertType.ERROR);
dialog.setTitle("Error Dialog");
dialog.setHeaderText("Look, an Error Dialog");
dialog.setContentText("Ooops, there was an error!\nOoops, there was an error!");
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
centerStage(stage, -10000, -10000);
dialog.show();
centerStage(stage, stage.getWidth(), stage.getHeight());
}

Resources