Изображение JavaFX соответствует ширине ScrollPane

Я пытаюсь загрузить изображение внутри ScrollPane и сделать так, чтобы изображение всегда соответствовало ширине ScrollPane, даже при изменении размера окна, так что вам нужно только прокручивать по вертикали. Я использую Scene Builder 8.5.0, и для свойства Fit To Width ScrollPane установлено значение true, но оно не работает, и изображение по-прежнему расширяется за пределы видимой ширины ScrollPane. Preserve Ratio также имеет значение true. Вот иерархия компонентов, которую я использовал для этого:

введите здесь описание изображения

Я также пытался установить свойство fit to width с помощью кода, но это тоже не работает.

imgScrollPane.setFitToWidth(true);

Я что-то упустил?


person V. Pantis    schedule 10.05.2021    source источник
comment
Вам необходимо убедиться, что свойство fitWidth представления изображения установлено на ширину окружающего AnchorPane. Быстрым и грязным способом было бы просто связать его, но это не совсем оптимальный подход: лучше создать пользовательскую панель для хранения ImageView и обновить свойство fitWidth ImageView в методе layoutChildren().   -  person James_D    schedule 10.05.2021


Ответы (1)


Как вы заметили, ваш подход с использованием AnchorPane работает не так, как вы ожидали.

Я согласен с комментарием от James_D и создал два примера. Первый пример — это «быстрый и грязный способ» с простым Binding между fitWidthProperty из ImageView и widthProperty из ScrollPane. Второй пример содержит небольшой образец класса, настроенный для ваших нужд, который переопределяет метод layoutChildren().

Пример 1 (быстрый и грязный с 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();
    }
}

Пример 2 (пользовательский класс с 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();
    }
}
person anko    schedule 10.05.2021