【问题标题】:JavaFX - Borders of ImageView and Pane do not scale / zoom properly inside ScrollPaneJavaFX - ImageView 和 Pane 的边框在 ScrollPane 内无法正确缩放/缩放
【发布时间】:2018-07-20 15:11:29
【问题描述】:

为了实现类似小地图的效果,我使用StackPanePane 叠加在ImageView 之上。我将StackPane 的缩放x 和y 属性绑定到Slider 以实现缩放效果。我在Pane 中添加了一些Circle 对象。这些圆圈当然也应该是可缩放的(它们是),但在这种情况下更重要的是,当缩放发生时,它们应该保持在它们的相对位置。下图显示了 GUI 到目前为止的样子。

到目前为止,我已经区分了两个有问题的案例。


问题 A - 位置正确但“超出范围”

在这个更简单的情况下,一切正常,除了放大图像似乎使它超出了StackPane 的范围。因此,您无法再滚动到图像的边框。查看下一个屏幕截图以了解我的意思。


问题 B - “在界内”但不在位置

为了使StackPane 适当增长,我将其大小属性绑定到缩放因子乘以图像大小。但是,我很确定这种方法会以某种方式与底层坐标结构混淆,因为现在圆圈“离开”其位置的比例因子 > 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();
    }
}

【问题讨论】:

    标签: image javafx javafx-8 scale zooming


    【解决方案1】:

    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()));
    

    【讨论】:

    • 我已经为此苦恼了两天多。谢谢!
    猜你喜欢
    • 2016-11-30
    • 2017-02-11
    • 1970-01-01
    • 2018-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 2019-05-18
    相关资源
    最近更新 更多