javafxfxml

JavaFX scene minWidth and minHeight not working


I tried the 2 following ways to set minHeight and minWidth for an AnchorPane in JavaFX (such that it is not resizable under 1280x720):

From the controller class (which is called from a Button in a login-view.fxml which has the same min and max values for height and width, but only locally and nothing is transferred to admin-view.fxml).

root, stage, scene are declared in LoginController, but they are not

root = FXMLLoader.load(getClass().getResource("admin-view.fxml"));
stage = (Stage) ((Node) event.getSource()).getScene().getWindow();


scene = new Scene(root);
stage.setScene(scene);
stage.setMinHeight(scene.getRoot().minHeight(-1));
stage.setMinWidth(scene.getRoot().minWidth(-1));

and

stage.setMinHeight(720);
stage.setMinWidth(1280);

and in admin-view.fxml

<VBox maxHeight="720.0" maxWidth="1280.0" minHeight="720.0" minWidth="1280.0" ...>
    <children>
    <VBox VBox.vgrow="ALWAYS" />
        <AnchorPane maxHeight="720.0" maxWidth="1280.0" minHeight="720.0" minWidth="1280.0">
    ... my code here ...
    <VBox VBox.vgrow="ALWAYS" />
    </children>
<VBox>

(I've selected the min and max values to the same because I saw in a tutorial that this should work).

But my problem is that the window's size is loading in 1280x720, but it is resizable to ~1260x690.


Solution

  • Problem Clarification

    Because you state: "I want the app to have a limit for resizing". I assume you want the stage to have a constant minimum size to be able to display content of a certain size, no matter what is displayed in it.

    Solution

    What you need to do is calculate the size of the frame around the content, then set the minimum size of the stage to the minimum size of the content, plus the frame size.

    Example Application

    Try the running the example application below and resizing the stage, monitoring the size values output to the console as you do so.

    The stage and scene will initially be sized to fit the preferred size of the scene content (800x600). The frame for the stage will be measured and the minimum size of the stage will be set to include the minimum scene size (600x400), plus the frame.

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class SizedStageApp extends Application {
        private static final double MIN_CONTENT_WIDTH = 600;
        private static final double MIN_CONTENT_HEIGHT = 400;
    
        private static final double PREF_CONTENT_WIDTH = 800;
        private static final double PREF_CONTENT_HEIGHT = 600;
    
        @Override
        public void start(Stage stage) throws Exception {
            StackPane root = new StackPane();
            root.layoutBoundsProperty().addListener((observable, oldLayoutBounds, newLayoutBounds) ->
                    System.out.println(
                            "New scene size: " + newLayoutBounds.getWidth() + " x " + newLayoutBounds.getHeight()
                    )
            );
    
            root.setMinSize(MIN_CONTENT_WIDTH, MIN_CONTENT_HEIGHT);
            root.setPrefSize(PREF_CONTENT_WIDTH, PREF_CONTENT_HEIGHT);
    
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
    
            System.out.println("Initial stage size: " + stage.getWidth() + " x " + stage.getHeight());
            System.out.println("Initial scene size: " + scene.getWidth() + " x " + scene.getHeight());
    
            double FRAME_WIDTH = stage.getWidth() - scene.getWidth();
            double FRAME_HEIGHT = stage.getHeight() - scene.getHeight();
    
            stage.setMinWidth(MIN_CONTENT_WIDTH + FRAME_WIDTH);
            stage.setMinHeight(MIN_CONTENT_HEIGHT + FRAME_HEIGHT);
    
            System.out.println("Min stage size: " + stage.getMinWidth() + " x " + stage.getMinHeight());
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    Notes on the Example

    The calculation and setting of the minimum size only need to be done once, after the stage is initially shown.

    If you replace the content in the stage (e.g. you change the scene or the root of the scene), the stage will retain its current size and also respect the previously set minimum size value. So you don't need to calculate and set a new minimum stage size if you change stage content.

    In the example code, I set the minimum and preferred size of the scene content root node in code rather than FXML, but setting the values in FXML would also work.