2
votes

I'm using SceneBuilder to create the View of my program. I need to have images inside GridPane nodes (cells), but the problem is that they should be fitted to the cell.

In other words, as soon as I resize the application window, the gridPade resizes accordingly but the images inside the cells stay fixed to the same size. Having the application window and all it's element resizable as well is a requirement that has been given to me, so I can't manage the view in a different way.

1

1 Answers

2
votes

Use ImageView.fitWidth and ImageView.fitHeight to set the size of the image. Assuming the children of your GridPane extend Region, you could do this in the layoutChildren method:

public class ImageCell extends Region {
    private final ImageView imageView;

    public ImageCell(Image image) {
        imageView = new ImageView(image);
        getChildren().add(imageView);
    }

    public ImageCell() {
        this(null);
    }

    public final void setImage(Image value) {
        imageView.setImage(value);
    }

    public final Image getImage() {
        return imageView.getImage();
    }

    public final ObjectProperty<Image> imageProperty() {
        return imageView.imageProperty();
    }

    @Override
    protected void layoutChildren() {
        super.layoutChildren();
        Insets insets = getInsets();
        double x = insets.getLeft();
        double y = insets.getTop();
        double width = getWidth() - x - insets.getRight();
        double height = getHeight() - y - insets.getBottom();

        Image image = getImage();
        double imageWidth = 0;
        double imageHeight = 0;
        if (image != null) {
            imageWidth = image.getWidth();
            imageHeight = image.getHeight();
        }

        // scale ImageView to available size
        double factor = Math.min(width / imageWidth, height / imageHeight);
        if (Double.isFinite(factor) && factor > 0) {
            imageView.setFitHeight(factor * imageHeight);
            imageView.setFitWidth(factor * imageWidth);
            imageView.setVisible(true);
        } else {
            imageView.setVisible(false);
        }

        // center ImageView in available area
        layoutInArea(imageView, x, y, width, height, 0, HPos.CENTER, VPos.CENTER);
    }

}

To fill the area you just need to make sure the GridPane grows the children:

@Override
public void start(Stage primaryStage) throws Exception {
    GridPane gridPane = new GridPane();
    RowConstraints rowConstraints = new RowConstraints();
    rowConstraints.setPercentHeight(50);
    ColumnConstraints columnConstraints = new ColumnConstraints();
    columnConstraints.setPercentWidth(50);

    gridPane.getRowConstraints().addAll(rowConstraints, rowConstraints);
    gridPane.getColumnConstraints().addAll(columnConstraints, columnConstraints);
    gridPane.addRow(0, new ImageCell(new Image("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/se/se-icon.png")),
            new ImageCell(new Image("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png")));
    gridPane.addRow(1, new ImageCell(new Image("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/sf/sf-icon.png")),
            new ImageCell(new Image("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/su/su-icon.png")));

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