我正在 JavaFX 中开发一个图像处理应用程序,其中涉及使用触摸板手势缩放图像。为了实现这一目标,我创建了
ScrollPane
的自定义实现,它可以使用熟悉的手势处理图像滚动和缩放。我已经包含了相关的代码片段和场景的 FXML 配置。
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>
ZoomableScrollPane 实例随后锚定到 TabPane,如下所示
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();
}
我遇到的问题与缩放图像的显示有关。当打开小图像并随后放大时,底部图像的一部分会被持续存在的空白区域重叠(可用屏幕截图)。 图像如下所示: 而预期是这样的:
其他人是否遇到过类似的问题,或者可以提供有关可能导致这种重叠空白问题的见解?
Javafx 组件会根据可用的大小自动调整自身。尝试删除 prefHeight 和 prefWidth,因为它会强制组件使用特定尺寸。