Reputation: 115
I'm trying to load an image inside a ScrollPane
and make the image always fit to the width of the ScrollPane
, even on window resize, so that you only have to scroll vertically. I'm using Scene Builder 8.5.0 and the Fit To Width property of the ScrollPane
is set to true, but it doesn't work and the image still expands beyond the visible width of the ScrollPane
. Preserve Ratio is also set to true. Here is the component hierarchy I used for this:
I also tried setting the fit to width property with code, but this doesn't work either
imgScrollPane.setFitToWidth(true);
Am I missing anything?
Upvotes: 0
Views: 856
Reputation: 1708
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();
}
}
Upvotes: 3