Karim Khasan
Karim Khasan

Reputation: 1

Empty space when scaling ImageView with custom ScrollPane in JavaFX

I am developing an image processing application in JavaFX that involves zooming images using touchpad gestures. To achieve this, I have created a custom implementation of ScrollPane that handles both image scrolling and zooming with familiar gestures. I have included relevant code snippets and the FXML configuration of the scene.

public class ZoomableScrollPane extends ScrollPane {
    private double scaleValue = 1;
    private double zoomIntensity = 0.02;
    private Node target;
    private Node zoomNode;

    public ZoomableScrollPane() {
        super();
    }

    public void setTarget(Node target) {
        this.target = target;
        this.zoomNode = new Group(target);
        setContent(outerNode(zoomNode));

        setPannable(true);
        setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setFitToHeight(true);
        setFitToWidth(true);

        updateScale();
    }

    private Node outerNode(Node node) {
        Node outerNode = centeredNode(node);
        outerNode.setOnScroll(e -> {
            e.consume();
            onScroll(e.getTextDeltaY(), new Point2D(e.getX(), e.getY()));
        });
        return outerNode;
    }

    private Node centeredNode(Node node) {
        VBox vBox = new VBox(node);
        vBox.setAlignment(Pos.CENTER);
        return vBox;
    }

    private void updateScale() {
        target.setScaleX(scaleValue);
        target.setScaleY(scaleValue);
    }

    private void onScroll(double wheelDelta, Point2D mousePoint) {
        double zoomFactor = Math.exp(wheelDelta * zoomIntensity);

        Bounds innerBounds = zoomNode.getLayoutBounds();
        Bounds viewportBounds = getViewportBounds();

        double valX = this.getHvalue() * (innerBounds.getWidth() - viewportBounds.getWidth());
        double valY = this.getVvalue() * (innerBounds.getHeight() - viewportBounds.getHeight());

        scaleValue = scaleValue * zoomFactor;
        updateScale();
        this.layout();

        Point2D posInZoomTarget = target.parentToLocal(zoomNode.parentToLocal(mousePoint));

        Point2D adjustment = target.getLocalToParentTransform().deltaTransform(posInZoomTarget.multiply(zoomFactor - 1));

        Bounds updatedInnerBounds = zoomNode.getBoundsInLocal();
        this.setHvalue((valX + adjustment.getX()) / (updatedInnerBounds.getWidth() - viewportBounds.getWidth()));
        this.setVvalue((valY + adjustment.getY()) / (updatedInnerBounds.getHeight() - viewportBounds.getHeight()));
    }
}
<VBox xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="640.0"
      xmlns="http://javafx.com/javafx/17.0.2-ea" fx:controller="ru.itmo.grafix.ui.controllers.MainSceneController">
    <MenuBar VBox.vgrow="NEVER">
      // Some menu stuff
    </MenuBar>
    <TabPane fx:id="tabPane" tabClosingPolicy="ALL_TABS" tabDragPolicy="REORDER"/>
</VBox>

The ZoomableScrollPane instance is then anchored to the TabPane as follows

private ImageView setImage(WritableImage img) {
    ImageView imageView = new ImageView(img);
    ZoomableScrollPane scrP = new ZoomableScrollPane();
    scrP.setPrefSize(tabPane.getPrefWidth(), tabPane.getPrefHeight());
    getActiveTab().setContent(scrP);
    scrP.setTarget(imageView);
    return imageView;
}

private Tab getActiveTab() {
    return tabPane.getSelectionModel().getSelectedItem();
}

The issue I am encountering is related to the display of zoomed images. When opening small images and subsequently zooming in, a portion of the image at the bottom becomes overlapped by an empty white space that persists (screenshots available). The image looks like this: broken display whereas expected to be like that: Normal image display

Has anyone else encountered a similar problem or can provide insights into what might be causing this overlapping empty white space issue?

Upvotes: 0

Views: 71

Answers (1)

Ken Karsson
Ken Karsson

Reputation: 1

Javafx components automatically adjust themselves according to the size available to them. Try removing the prefHeight and prefWidth, as it forces the components to use a particular dimension.

Upvotes: 0

Related Questions