JavaFX - ImageView 和 Pane 的边框在 ScrollPane 内不能正确缩放/缩放
JavaFX - Borders of ImageView and Pane do not scale / zoom properly inside ScrollPane
为了实现类似 迷你地图 的效果,我使用了 StackPane
在 ImageView
之上叠加了 Pane
。我将 StackPane
的缩放 x 和 y 属性绑定到 Slider
以实现缩放效果。我向 Pane
添加了一些 Circle
个对象。这些圆圈当然也应该是可缩放的(确实如此),但在这种情况下更重要的是,当缩放发生时,它们 应该保持在它们的相对位置 。下图显示了 GUI 目前的样子。
到目前为止,我已经区分了两个有问题的案例。
问题 A - 正确的位置但是 'out of bounds'
在这个更简单的例子中,一切正常,只是放大图像似乎超出了 StackPane
的范围。因此,您无法再滚动到图像的边框。查看下一个屏幕截图以了解我的意思。
问题 B - 'In bounds' 但位置不对
为了使 StackPane
适当增长,我将其大小属性绑定到缩放因子乘以图像大小。但是,我很确定这种方法会以某种方式混淆底层坐标结构,因为现在圆 'leaves' 其位置的比例因子 > 1。在最后一个屏幕截图中描述了上述行为。
我在下面添加了我的代码。任何帮助将不胜感激:)
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ScalingProblem extends Application {
private static final String IMAGE_URL = "https://st2.depositphotos.com/3034795/10774/i/950/depositphotos_107745620-stock-photo-labyrinth-or-maze.jpg";
@Override
public void start(Stage primaryStage) throws Exception {
// Prepare the main part of the GUI.
Image backgroundImage = new Image(IMAGE_URL);
ImageView imageView = new ImageView(backgroundImage);
Circle circle = new Circle(40, Color.ORANGE);
circle.setStroke(Color.BLUE);
circle.setStrokeWidth(5);
Pane layer = new Pane(circle);
StackPane stackPane = new StackPane(imageView, layer);
ScrollPane scrollPane = new ScrollPane(stackPane);
scrollPane.setPannable(true);
// Prepare the controls on the left side.
Slider xSlider = new Slider();
Slider ySlider = new Slider();
Slider radiusSlider = new Slider();
Slider zoomSlider = new Slider();
VBox vBox = new VBox(xSlider, ySlider, radiusSlider, zoomSlider);
vBox.setSpacing(10);
vBox.setPrefWidth(200);
// Adjust the sliders.
adjustSlider(xSlider, 0, 1000, 50);
adjustSlider(ySlider, 0, 1000, 50);
adjustSlider(radiusSlider, 0, 100, 15);
adjustSlider(zoomSlider, 0, 3, 1);
zoomSlider.setMajorTickUnit(1);
zoomSlider.setMinorTickCount(1);
zoomSlider.setShowTickMarks(true);
zoomSlider.setShowTickLabels(true);
// Do all necessary binding.
circle.centerXProperty().bind(xSlider.valueProperty());
circle.centerYProperty().bind(ySlider.valueProperty());
circle.radiusProperty().bind(radiusSlider.valueProperty());
stackPane.scaleXProperty().bind(zoomSlider.valueProperty());
stackPane.scaleYProperty().bind(zoomSlider.valueProperty());
/*
* So far, I always needed to make the StackPane's size grow / shrink depending on the zoom level. If the
* following two lines are commented out, zooming in will make the ImageView exceed the bounds of the StackPane.
* As a result, the StackPane does not 'grow' appropriately so that you cannot pan the view to see the edges of
* the background.
*/
stackPane.prefWidthProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getWidth()));
stackPane.prefHeightProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getHeight()));
// Piece the GUI together.
BorderPane root = new BorderPane();
root.setCenter(scrollPane);
root.setLeft(vBox);
root.setPrefHeight(300);
root.setPrefWidth(500);
// Show the stage.
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private void adjustSlider(Slider slider, double min, double max, double start) {
slider.setMin(min);
slider.setMax(max);
slider.setValue(start);
}
public static void main(String[] args) {
launch();
}
}
ScrollPane
使用未修改的布局边界来确定内容大小。这不包括缩放变换。为防止内容超出可滚动区域,将缩放节点包裹在 Group
.
中
像这样修改 ScrollPane
创建:
ScrollPane scrollPane = new ScrollPane(new Group(stackPane));
并删除对 prefWidth
/prefHeight
的绑定,即删除以下行:
stackPane.prefWidthProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getWidth()));
stackPane.prefHeightProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getHeight()));
为了实现类似 迷你地图 的效果,我使用了 StackPane
在 ImageView
之上叠加了 Pane
。我将 StackPane
的缩放 x 和 y 属性绑定到 Slider
以实现缩放效果。我向 Pane
添加了一些 Circle
个对象。这些圆圈当然也应该是可缩放的(确实如此),但在这种情况下更重要的是,当缩放发生时,它们 应该保持在它们的相对位置 。下图显示了 GUI 目前的样子。
到目前为止,我已经区分了两个有问题的案例。
问题 A - 正确的位置但是 'out of bounds'
在这个更简单的例子中,一切正常,只是放大图像似乎超出了 StackPane
的范围。因此,您无法再滚动到图像的边框。查看下一个屏幕截图以了解我的意思。
问题 B - 'In bounds' 但位置不对
为了使 StackPane
适当增长,我将其大小属性绑定到缩放因子乘以图像大小。但是,我很确定这种方法会以某种方式混淆底层坐标结构,因为现在圆 'leaves' 其位置的比例因子 > 1。在最后一个屏幕截图中描述了上述行为。
我在下面添加了我的代码。任何帮助将不胜感激:)
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ScalingProblem extends Application {
private static final String IMAGE_URL = "https://st2.depositphotos.com/3034795/10774/i/950/depositphotos_107745620-stock-photo-labyrinth-or-maze.jpg";
@Override
public void start(Stage primaryStage) throws Exception {
// Prepare the main part of the GUI.
Image backgroundImage = new Image(IMAGE_URL);
ImageView imageView = new ImageView(backgroundImage);
Circle circle = new Circle(40, Color.ORANGE);
circle.setStroke(Color.BLUE);
circle.setStrokeWidth(5);
Pane layer = new Pane(circle);
StackPane stackPane = new StackPane(imageView, layer);
ScrollPane scrollPane = new ScrollPane(stackPane);
scrollPane.setPannable(true);
// Prepare the controls on the left side.
Slider xSlider = new Slider();
Slider ySlider = new Slider();
Slider radiusSlider = new Slider();
Slider zoomSlider = new Slider();
VBox vBox = new VBox(xSlider, ySlider, radiusSlider, zoomSlider);
vBox.setSpacing(10);
vBox.setPrefWidth(200);
// Adjust the sliders.
adjustSlider(xSlider, 0, 1000, 50);
adjustSlider(ySlider, 0, 1000, 50);
adjustSlider(radiusSlider, 0, 100, 15);
adjustSlider(zoomSlider, 0, 3, 1);
zoomSlider.setMajorTickUnit(1);
zoomSlider.setMinorTickCount(1);
zoomSlider.setShowTickMarks(true);
zoomSlider.setShowTickLabels(true);
// Do all necessary binding.
circle.centerXProperty().bind(xSlider.valueProperty());
circle.centerYProperty().bind(ySlider.valueProperty());
circle.radiusProperty().bind(radiusSlider.valueProperty());
stackPane.scaleXProperty().bind(zoomSlider.valueProperty());
stackPane.scaleYProperty().bind(zoomSlider.valueProperty());
/*
* So far, I always needed to make the StackPane's size grow / shrink depending on the zoom level. If the
* following two lines are commented out, zooming in will make the ImageView exceed the bounds of the StackPane.
* As a result, the StackPane does not 'grow' appropriately so that you cannot pan the view to see the edges of
* the background.
*/
stackPane.prefWidthProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getWidth()));
stackPane.prefHeightProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getHeight()));
// Piece the GUI together.
BorderPane root = new BorderPane();
root.setCenter(scrollPane);
root.setLeft(vBox);
root.setPrefHeight(300);
root.setPrefWidth(500);
// Show the stage.
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private void adjustSlider(Slider slider, double min, double max, double start) {
slider.setMin(min);
slider.setMax(max);
slider.setValue(start);
}
public static void main(String[] args) {
launch();
}
}
ScrollPane
使用未修改的布局边界来确定内容大小。这不包括缩放变换。为防止内容超出可滚动区域,将缩放节点包裹在 Group
.
像这样修改 ScrollPane
创建:
ScrollPane scrollPane = new ScrollPane(new Group(stackPane));
并删除对 prefWidth
/prefHeight
的绑定,即删除以下行:
stackPane.prefWidthProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getWidth()));
stackPane.prefHeightProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getHeight()));