JavaFX 通过拖放在 ScrollPane 中移动对象

JavaFX moving Objects within ScrollPane by drag and drop

我在 ScrollPane 中有一个非常大的 StackPane(3000x2000)。这个想法是像一个大 "drawing board" 一样使用它,用户可以在其中创建节点并将它们拖来拖去,以创建思维导图等。问题是拖放:如果 scrollPane 在它的 "start position" 中,它工作正常,因此 Hvalue 和 Vvalue 都是 0。但是一旦你滚动了一下,DragEvent.getX() 和 . getY() return 相对于窗格的可见部分,而不是其整个大小。这意味着您无法正确拖放某些东西。我创建了一个测试 class 来说明问题,没有任何过时的代码:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class DragTestClass extends Application{

    public static void problem(Circle circle, ScrollPane scrollPane, StackPane pane, DataFormat dataFormat){
        circle.setOnDragDetected(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    Dragboard db = circle.startDragAndDrop(TransferMode.ANY);
                    ClipboardContent content = new ClipboardContent();
                    content.put(dataFormat,0); // normally, ID of node
                    db.setContent(content);
                    event.consume();
                }
            });

        scrollPane.setOnDragDropped(new EventHandler<DragEvent>() {
                @Override
                public void handle(DragEvent event) {
                    Dragboard db = event.getDragboard();
                    if(db.hasContent(dataFormat) && db.getContent(dataFormat) instanceof Integer){
                        int index = (Integer) db.getContent(dataFormat);
                        Circle node = (Circle) pane.getChildren().get(index);
                        node.setManaged(false);
                        // this is the problematic part
                        node.setTranslateX(event.getX() - node.getCenterX());
                        node.setTranslateY(event.getY() - node.getCenterY());

                        event.setDropCompleted(true);
                        event.consume();
                    }
                }
        });

        scrollPane.setOnDragOver(new EventHandler<DragEvent>() {
            public void handle(DragEvent event) {
                event.acceptTransferModes(TransferMode.ANY);
                event.consume();
            }
        });
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        ScrollPane scrollPane = new ScrollPane();
        StackPane pane = new StackPane();
        DataFormat dataFormat = new DataFormat("DragDropFormat");
        int width = 1000;
        int height = 1000;
        pane.setMinHeight(height);
        pane.setMaxHeight(height);
        pane.setMinWidth(width);
        pane.setMaxWidth(width);
        Circle circle = new Circle(50,50,20); // normally a StackPane
        circle.setManaged(false);
        pane.getChildren().add(circle);
        pane.setAlignment(Pos.TOP_LEFT);
        scrollPane.setContent(pane);

        problem(circle, scrollPane, pane, dataFormat);

        Scene scene = new Scene(scrollPane, 400, 400);
        primaryStage.setTitle("Problem");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

我的想法是在节点的平移中添加一些东西,比如 scrollPane.getHvalue() * width,但这似乎不起作用。也许我只是用谷歌搜索了错误的关键字,但我没有找到任何有用的东西,所以如果这个问题在其他地方得到了回答,我很抱歉。预先感谢您的帮助!

我想通了!在 StackPane 上设置 EventHandler(ScrollPane 的内容,而不是 ScrollPane 本身)达到了目的。显然,event.getX() returns 的坐标是相对于具有 EventHandler 的节点的。在这个例子中:

pane.setOnDragDropped...