user15491771
user15491771

Reputation:

Maintain Gridpane the same height and width (Aspect ratio)

I have a javafx GridPane which which resizes itself to fit the dimensions of the Stage when I resize the stage. I want the height of the gridpane to match the width of the gridpane and thus resize to the maximum possible size maintaining this constraints.

I had to add more elements inside the parent of the GridPane. I found that the elements added were not behaving normally at all, and overlapping on top of each other.

Of course they stopped overlapping when I removed the overriding methods, but then again as I resize my stage the grid pane does not maintain a perfect square.

I thought of trying to use an image/imageView in the background and apply setPreserveRatio(true) for it. Then bind the heightProperty of this image to the gridPane's prefHeightProperty, but for some reason this is also not yeilding me any results.

Here is an MCVE of the second approach which is not working, but will be great if I can somehow make this work.

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        StackPane stackPane = new StackPane();

        Image image = new Image("Square Image.png", 300, 300, true, true);
        ImageView imageView = new ImageView(image);
        // This makes the image resize while maintaining its square shape...
        imageView.fitHeightProperty().bind(stackPane.heightProperty());
        imageView.fitWidthProperty().bind(stackPane.widthProperty());
        imageView.setPreserveRatio(true);

        GridPane gridPane = new GridPane();
        for(int i=0; i<5; i++) {
            for (int j = 0; j < 5; j++) {
                Pane pane = new Pane();
                pane.setPrefSize(100, 100);
                gridPane.add(pane, i, j);
            }
        }
        // Does not work as intended... :(
        gridPane.prefWidthProperty().bind(imageView.fitWidthProperty());
        gridPane.prefHeightProperty().bind(imageView.fitHeightProperty());
        
        /*
        Tried this as well, also does not work.. :(
        gridPane.prefWidthProperty().bind(image.widthProperty());
        gridPane.prefHeightProperty().bind(image.heightProperty());
        */


        gridPane.setGridLinesVisible(true);

        stackPane.getChildren().addAll(imageView, gridPane);
        primaryStage.setScene(new Scene(stackPane));
        primaryStage.show();
    }
  
    public static void main(String[] args) {
        launch(args);
    }
}

Of course all of these approaches are cheap hacky methods of trying to get this done. If there is a standard way of doing it which I dont know then I would like to know that instead.

Upvotes: 4

Views: 1658

Answers (1)

c0der
c0der

Reputation: 18792

Encapsulate the GridPane in a StackPane and use binding to dynamically change GridPane children preferred size while maintaining aspect ratio:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.stage.Stage;

    public class Main extends Application {

        private final int SIZE = 5;

        @Override
        public void start(Stage primaryStage) {

            GridPane gridPane = new GridPane();
            gridPane.setAlignment(Pos.CENTER);

            StackPane centerPane = new StackPane(gridPane);
            centerPane.setStyle("-fx-background-color:cyan");
            centerPane.setPrefSize(SIZE*50, SIZE*50);

            for(int i=0; i<SIZE; i++) {
                for (int j = 0; j < SIZE; j++) {
                    Pane pane = new Pane();
                    pane.setStyle("-fx-background-color:red");
                    gridPane.add(pane, i, j);
                    pane.prefWidthProperty().bind(Bindings.min(centerPane.widthProperty().divide(SIZE),
                                                                centerPane.heightProperty().divide(SIZE)));
                    pane.prefHeightProperty().bind(Bindings.min(centerPane.widthProperty().divide(SIZE),
                                                                centerPane.heightProperty().divide(SIZE)));
                }
            }
            gridPane.setGridLinesVisible(true);

            primaryStage.setScene(new Scene(centerPane));
            primaryStage.show();
        }

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

enter image description here

Upvotes: 3

Related Questions