41

How do I get an image in an ImageView to automatically resize such that it always fits the parent node?

Here is a small code example:

@Override
public void start(Stage stage) throws Exception {
    BorderPane pane = new BorderPane();
    ImageView img = new ImageView("http://...");

    //didn't work for me:
    //img.fitWidthProperty().bind(new SimpleDoubleProperty(stage.getWidth())); 

    pane.setCenter(img);

    Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.show();
}
The Unfun Cat
  • 29,987
  • 31
  • 114
  • 156
rbs
  • 1,087
  • 2
  • 17
  • 24
  • 3
    Related question: [How to resize an image when resizing the window in JavaFX](http://stackoverflow.com/questions/22993550/how-to-resize-an-image-when-resizing-the-window-in-javafx/22997981?noredirect=1#36027997) – jewelsea Mar 16 '16 at 12:26

6 Answers6

66
@Override
public void start(Stage stage) throws Exception {
    BorderPane pane = new BorderPane();
    ImageView img = new ImageView("http://...");

    img.fitWidthProperty().bind(stage.widthProperty()); 

    pane.setCenter(img);

    Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.show();
}
The Unfun Cat
  • 29,987
  • 31
  • 114
  • 156
  • 3
    JavaFX2 is easy, but not always self-explanatory. Once you get used to the concepts it is a breeze though. – The Unfun Cat Sep 28 '12 at 11:31
  • 13
    \*facepalm\* Really? The layout system can't do this itself? – Aleksandr Dubinsky Jan 31 '14 at 20:46
  • I faced a similar problem with an ImageView because it does *not* automatically fit to its parent. I now needed a means to get the maximum available width and height (my layout was much more complex, so simply taking the stage's or BorderPane's width was not an option). The simplest solution I found is to wrap the ImageView in a VBox, which does fortunately fit to its parent by default, and to bind the ImageView's size attributes to the VBox' size attributes (analogous to the code above). – ComFreek May 31 '14 at 15:12
  • 20
    how can I set it in the fxml – Tomi Oct 16 '15 at 08:30
  • 3
    I chose: `img.setPreserveRatio(true); img.fitWidthProperty().bind(stage.widthProperty()); img.fitHeightProperty().bind(stage.heightProperty());` – Steve Pitchers Feb 09 '16 at 18:20
  • Really? Are you telling me that there is no way to do this in FXML? – Yassir Khaldi Aug 31 '21 at 13:51
16

This is a better solution than binding the width property (better because often when binding a child to its container, it might not be possible to make the container smaller. At other ocasions the container might even automatically start growing).

The solution below relies on overriding an ImageView so that we can let it behave as 'resizable' and then providing implementations for the minimum ,preferred, and maximum width/heights. Also important is to actually implement the resize() call.

class WrappedImageView extends ImageView
{
    WrappedImageView()
    {
        setPreserveRatio(false);
    }

    @Override
    public double minWidth(double height)
    {
        return 40;
    }

    @Override
    public double prefWidth(double height)
    {
        Image I=getImage();
        if (I==null) return minWidth(height);
        return I.getWidth();
    }

    @Override
    public double maxWidth(double height)
    {
        return 16384;
    }

    @Override
    public double minHeight(double width)
    {
        return 40;
    }

    @Override
    public double prefHeight(double width)
    {
        Image I=getImage();
        if (I==null) return minHeight(width);
        return I.getHeight();
    }

    @Override
    public double maxHeight(double width)
    {
        return 16384;
    }

    @Override
    public boolean isResizable()
    {
        return true;
    }

    @Override
    public void resize(double width, double height)
    {
        setFitWidth(width);
        setFitHeight(height);
    }
}
  • Thank you, that was relly helpful – olivierr91 Oct 16 '16 at 21:15
  • For people like me who also wanted it center, look over here https://stackoverflow.com/questions/32781362/centering-an-image-in-an-imageview; instead of setX setY use setTranslateX setTranslateY, put the center call inside resize method. – BWC semaJ Feb 01 '18 at 10:23
  • How would I use this with an @FXML file? – Carrein Mar 03 '19 at 11:56
5

Use ScrollPane or simply Pane to overcome this problem: Example:

 img_view1.fitWidthProperty().bind(scrollpane_imageview1.widthProperty()); 
 img_view1.fitHeightProperty().bind(scrollpane_imageview1.heightProperty());
Cfreak
  • 19,191
  • 6
  • 49
  • 60
Akshay Goyal
  • 61
  • 1
  • 1
1

If you want the ImageView to fit inside a windows frame, use this line of code: imageView.fitWidthProperty().bind(scene.widthProperty()).

Note that I am using widthProperty of the scene not the stage. Example:

import java.io.FileNotFoundException;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;

public class MapViewer extends Application {

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

    @Override
    public void start(Stage primaryStage) throws FileNotFoundException {
        String strTitle = "Titulo de la Ventana";
        int w_width = 800;
        int w_height = 412;
        primaryStage.setTitle(strTitle);
        primaryStage.setWidth(w_width);
        primaryStage.setHeight(w_height);

        Group root = new Group();
        Scene scene = new Scene(root);

        final ImageView imv = new ImageView("file:C:/Users/utp/Documents/1.2008.png");
        imv.fitWidthProperty().bind(scene.widthProperty());
        imv.setPreserveRatio(true);

        root.getChildren().add(imv);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

}

The aspect radio of the stage (primaryStage) should be similar to that of the image (1.2008.png)

dew
  • 21
  • 2
0

This is a calculated width method that removes the width of the scroll bar.

first:
myImageView.setPreserveRatio(true);

monitor scrollbar width changes:

scrollPane.widthProperty().addListener((observable, oldValue, newValue) -> {
            myImageView.setFitWidth(newValue.doubleValue() - (oldValue.doubleValue() - scrollPane.getViewportBounds().getWidth()));
        });

scrollBar width:
oldValue.doubleValue() - scrollPane.getViewportBounds().getWidth()

How do I set init width?
after primaryStage.show();

myImageView.setFitWidth(scrollPane.getViewportBounds().getWidth());

0

Fill the parent whit aspect ration, this fix the problem whit when parent height and width are not in proper ration like the image.

Image image = new Image(getClass().getResource(%path%).toString());
double ratio = image.getWidth() / image.getHeight();
double width = stage.getScene().getWidth();

ImageView imageView.setImage(image);
imageView.setFitWidth(width);
imageView.setFitHeight(width/ratio);
imageView.setPreserveRatio(true);
Vasil Valchev
  • 5,701
  • 2
  • 34
  • 39