Set Height and Width of Stage and Scene in javafx
Asked Answered
K

3

18
  • I develop one javafx application.
  • In my application there are two scenes and one stage.
  • In application the height and width for both scenes are same or constant.
  • so as per my research the height and width for scene remain constant which mention in the constructor but the scene adjust itself with height and width of stage.
  • when i lunch application with the height and width of stage which is different than the constant height and width of scene then scene adjust with stage.
  • but when at the run time when i apply the 2nd scene then scene is not adjust with height and width of stage.the height and width of scene remain constant.

  • so any solution?

Kedah answered 25/9, 2013 at 7:23 Comment(1)
The stage need to be refresh but how?Kedah
K
12

As I understand the problem above posted. I think the stage is good enough to set the preferred height and width as per the listener get the newer request to apply on the windows size. But it has some limitations, if you maximize or minimize the javaFX screen and will try to navigate to other screen then other screen will be having same window size but the scene content will distorted into the default height and width of it, e.g take a login and home scene in javafx (all scene is screated with fxml). Login.fxml is initialized by its controller. As you have mentioned that scene is initialized in constructor, so it must be the controller of the related fxml(as of now FXML is tight coupled with controller). You are going to set the scene size(height & width) in constructor itself.

1.) LoginController for login.fxml

 import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;

    import java.io.IOException;

    class LoginController  {

        private Stage stage;
        private Scene scene;
        private Parent parent;
        @FXML  
        private Button gotoHomeButton;        

        public LoginController()  throws Exception {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/login.fxml"));
            fxmlLoader.setController(this);
            try {
                parent = (Parent) fxmlLoader.load();
                // set height and width here for this login scene
                scene = new Scene(parent, 1000, 800);
            } catch (IOException ex) {
                System.out.println("Error displaying login window");
                throw new RuntimeException(ex);
            }
        }

        // create a launcher method for this. Here I am going to take like below--
        public void launchLoginScene(Stage stage) {
           this.stage = stage;
            stage.setScene(scene);
            stage.setResizable(true);

            stage.widthProperty().addListener(new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) {
                    setCurrentWidthToStage(number2); 
                }
            });

            stage.heightProperty().addListener(new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) {
                    setCurrentHeightToStage(number2);
                }
            });

            //Don't forget to add below code in every controller
            stage.hide();
            stage.show();

        }

         @FXML
        public void authenticateUser(ActionEvent actionEvent) { 

        // write your logic to authenticate user


         // 
         new HomeController().displayHomeScreen(stage);

        } 

        private void setCurrentWidthToStage(Number number2) {
            stage.setWidth((double) number2);
        }

        private void setCurrentHeightToStage(Number number2) {
            stage.setHeight((double) number2);
        }
    }

2.) Same for HomeController --

public class HomeController {

    private Parent parent;
    private Stage stage;
    private Scene scene;


    public HomeController (){
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/home.fxml"));
        fxmlLoader.setController(this);
        try {
             parent = (Parent) fxmlLoader.load();
                // set height and width here for this home scene
                scene = new Scene(parent, 1000, 800);
        } catch (IOException e) {
         // manage the exception
        }
    }

    public void displayHomeScreen(Stage stage){
        this.stage = stage;
        stage.setScene(scene); 

        // Must write
        stage.hide()
        stage.show();
    }
}

3.) Main class

import javafx.application.Application;

import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        new LoginController().launchLoginScene(primaryStage);
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Just try to put Stage.hide() before Stage.show() in every controller. I hope this will help you out.

Kirov answered 25/10, 2013 at 11:47 Comment(1)
Great answer! This is strange thing (in JavaFX) to update size by listening... size (Scene has high priority) imho. It seems auto mode must be presented. But code works fine. Thank you.Grammalogue
P
9

That is because the Stage adapts its size to the scene, unless explicitly instructed diferently...

To here is one solution:

stage.setScene(scene2);
stage.setHeight(1000);
stage.setWidth(1000);

And a sample application:

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.AnchorPane;
import javafx.stage.Stage;

public class Test extends Application {

    @Override
    public void start(final Stage stage) throws Exception {

        AnchorPane anchor1 = new AnchorPane();
        final Scene scene1 = new Scene(anchor1, 250, 250);
        Button boton1 = new Button();
        anchor1.getChildren().add(boton1);

        AnchorPane anchor2 = new AnchorPane();
        final Scene scene2 = new Scene(anchor2, 500, 500);
        Button boton2 = new Button();
        anchor2.getChildren().add(boton2);

        boton2.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent arg0) {
                // TODO Auto-generated method stub
                stage.setScene(scene1);
                stage.setHeight(1000);
                stage.setWidth(1000);
            }
        });

        boton1.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent arg0) {
                // TODO Auto-generated method stub
                stage.setScene(scene2);
                stage.setHeight(1000);
                stage.setWidth(1000);
            }
        });
        stage.setScene(scene1);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Parnas answered 26/9, 2013 at 11:42 Comment(2)
The sample posted by you is right the concept of applying height and width to stage is also right.but if you apply background image to both scene and change the size of stage(try different size) on click event of both button then you will figure out actual problem.at second time the scene will not get adjust with the stage..........so i need a way to refresh the stage.Kedah
The stage.sizeToScene() is right concept but i want scene to get adjust with stage.Kedah
C
2

I know this is an old topic, but this (bug?) still persists in Java7u75.

I ran into the same issue... the solution offered by shambhu above does work, but results in a visible "window switching" effect:

stage.hide();
stage.show();

I found that the following code solves the problem (gets the stage to "refresh") without any visible effects:

final boolean resizable = stage.isResizable();
stage.setResizable(!resizable);
stage.setResizable(resizable);
Clerc answered 13/6, 2015 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.