As you noticed your approach with the use of an AnchorPane
does not work as you expected.
I agree with the comment from James_D and created two examples. The first example is the „quick-and-dirty way“ with a simple Binding
between the fitWidthProperty
of the ImageView
and the widthProperty
of the ScrollPane
. The second example contains a little sample class customized for your needs which overrides the layoutChildren()
method.
Example 1 (quick-and-dirty with Binding
):
package org.example;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import java.util.Optional;
public class App extends Application {
@Override
public void start(Stage stage) {
String imageUrl = "https://images.freeimages.com/images/large-previews/2e9/fisherman-in-the-lighthouse-1496152.jpg";
Image image = new Image(imageUrl);
ImageView imageView = new ImageView(image);
imageView.setPreserveRatio(true);
ScrollPane scrollPane = new ScrollPane(imageView);
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
// Example of how the Binding could be (here: take into account if the vertical scroll bar is showing or not):
imageView.fitWidthProperty().bind(Bindings.createDoubleBinding(() -> {
// Find the vertical scroll bar of the scroll pane:
Optional<ScrollBar> verticalScrollBarOpt = scrollPane.lookupAll(".scroll-bar").stream()
.filter(node -> node instanceof ScrollBar)
.map(node -> (ScrollBar) node)
.filter(scrollBar -> scrollBar.getOrientation() == Orientation.VERTICAL).findAny();
if (verticalScrollBarOpt.isPresent() && verticalScrollBarOpt.get().isVisible())
return scrollPane.getWidth() - verticalScrollBarOpt.get().getWidth();
else
return scrollPane.getWidth();
}, scrollPane.widthProperty()));
stage.setScene(new Scene(scrollPane, 1300, 600));
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Example 2 (custom class with layoutChildren()
):
package org.example;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
public class App extends Application {
@Override
public void start(Stage stage) {
String imageUrl = "https://images.freeimages.com/images/large-previews/2e9/fisherman-in-the-lighthouse-1496152.jpg";
Image image = new Image(imageUrl);
ImageView imageView = new ImageView(image);
imageView.setPreserveRatio(true);
CustomImagePane customImagePane = new CustomImagePane(imageView);
ScrollPane scrollPane = new ScrollPane(customImagePane);
scrollPane.setFitToWidth(true);
stage.setScene(new Scene(scrollPane, 1300, 600));
stage.show();
}
/**
* A simplified example how your custom control could look like.
*/
public class CustomImagePane extends Region {
private final ObjectProperty<ImageView> imageView = new SimpleObjectProperty<>();
public CustomImagePane(ImageView imageView) {
this.imageView.addListener((observable, oldValue, newValue) -> {
if (oldValue != null)
getChildren().remove(oldValue);
if (newValue != null)
getChildren().add(newValue);
});
this.imageView.set(imageView);
}
@Override
protected void layoutChildren() {
ImageView imageView = getImageView();
if (imageView != null) {
imageView.setFitWidth(getWidth());
imageView.setFitHeight(0);
layoutInArea(imageView, 0, 0, getWidth(), getHeight(), 0, HPos.CENTER, VPos.CENTER);
}
super.layoutChildren();
}
public ImageView getImageView() {
return imageView.get();
}
public ObjectProperty<ImageView> imageViewProperty() {
return imageView;
}
public void setImageView(ImageView imageView) {
this.imageView.set(imageView);
}
}
public static void main(String[] args) {
launch();
}
}