Reputation: 1
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
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