简体   繁体   中英

JavaFX image fit to the width of ScrollPane

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?

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();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM