How to set a GridPane to adjust automatically to content in JavaFX

I have a GridPane inside of a ScrollView. I'm adding images in each space of the GridPane. First there is only 1 row and 3 columns. But when I pass the amount of 3 images, I increase the GridPane in one row and I add the number (130px) that represents the height of a grid row. So here is my code.

 private void AddItem() {
        ImageView image = new ImageView();
        image.setImage(new Image("media/logo.jpg"));
        image.setFitHeight(50);
        image.setFitWidth(100);
        if (columns > 2) {//when it reaches the end of the columns
            viewGrid.setPrefHeight(viewGrid.getHeight() + 130);//I increase the height of the GridPane
            viewGrid.addRow(rows++);//I add a new row
            columns=0;//I set the column to 0 again
        }

        viewGrid.add(image, columns, rows);
        columns++;
 }

Result

The images started to smash into each other instead of keeping the real position:

enter image description here

Is there some property in GridPane that allows me to achieve the desired behavior?

Upvotes: 1

Views: 6702

Answers (1)

fabian
fabian

Reputation: 82531

Don't manually adjust the size of the GridPane. Use rowConstraints instead. Those allow you to specify properties for a row, such as alignment and size constraints. The GridPane will automatically update it's height.

Example

private static final int COLUMN_COUNT = 3;
private int nextColumnIndex = COLUMN_COUNT;
private int currentRow = -1;

@Override
public void start(Stage primaryStage) {
    Image image = new Image("http://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png?v=c78bd457575a");
    
    GridPane imagePane = new GridPane();
    
    ColumnConstraints colConstraint = new ColumnConstraints(120);
    colConstraint.setHalignment(HPos.LEFT);
    
    RowConstraints rowConstraints = new RowConstraints(130);
    rowConstraints.setValignment(VPos.CENTER);
    
    // add constraints for columns
    imagePane.getColumnConstraints().addAll(colConstraint, colConstraint, colConstraint);

    ScrollPane scroll = new ScrollPane(imagePane);
    scroll.setFitToWidth(true);
    scroll.setPrefSize(380, 300);

    BorderPane root = new BorderPane(scroll);

    Button btn = new Button("Add Image");
    btn.setOnAction((ActionEvent event) -> {
        ImageView newImage = new ImageView(image);
        newImage.setFitHeight(50);
        newImage.setFitWidth(100);
        if (nextColumnIndex >= COLUMN_COUNT) {
            nextColumnIndex = 0;
            currentRow++;
            imagePane.getRowConstraints().add(rowConstraints);
        }
        imagePane.addRow(currentRow, newImage);
        nextColumnIndex++;
    });

    root.setLeft(new VBox(btn));

    Scene scene = new Scene(root);

    primaryStage.setScene(scene);
    primaryStage.show();
}

By the way: The addRow method is used to add children to a specific row, not for adding the row itself. A row is automatically added to the GridPane, if a Node with the index (or a larger index) is added as child. You need not create a row by calling a GridPane method.


Note that behaviour similar to the one you're trying to achieve is already implemented in FlowPane. This would be an option to simplify your code. Just make sure the width of the FlowPane is chosen appropriately (i.e. allowing 3, but not 4 elements in a row).

Example

@Override
public void start(Stage primaryStage) {
    Image image = new Image("http://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png?v=c78bd457575a");

    FlowPane imagePane = new FlowPane();
    imagePane.setHgap(20);
    imagePane.setVgap(130 - 50);
    imagePane.setRowValignment(VPos.CENTER);
    imagePane.setColumnHalignment(HPos.LEFT);

    ScrollPane scroll = new ScrollPane(imagePane);
    scroll.setFitToWidth(true);
    scroll.setPrefSize(380, 300);

    BorderPane root = new BorderPane(scroll);

    Button btn = new Button("Add Image");
    btn.setOnAction((ActionEvent event) -> {
        ImageView newImage = new ImageView(image);
        newImage.setFitHeight(50);
        newImage.setFitWidth(100);
        imagePane.getChildren().add(newImage);
    });

    root.setLeft(new VBox(btn));

    Scene scene = new Scene(root);

    primaryStage.setScene(scene);
    primaryStage.show();
}

Upvotes: 2

Related Questions