【问题标题】:JavaFX detecting mouse eventsJavaFX 检测鼠标事件
【发布时间】:2021-05-15 14:10:43
【问题描述】:

我正在尝试将节点从一个窗口拖放到另一个窗口。该代码创建了两个窗口,并在其中一个窗口中添加了一个可拖动标签。目标是将节点从一个窗口移动到另一个窗口并再次返回。这是我目前拥有的。

public class Main extends Application {

    private static Node transferNode;

    @Override
    public void start(Stage primaryStage) {
        initFirstWindow();
        initSecondWindow();
    }

    public static void initFirstWindow() {
        BorderPane borderPane = new BorderPane();
        Label label = new Label("clickable");
        label.setOnDragDetected(event -> {
            label.startFullDrag();
            System.out.println("Full drag");
            event.consume();
        });
        borderPane.setCenter(label);

        Stage stage = new Stage();
        stage.setTitle("Window number 1");
        stage.setScene(new Scene(borderPane, 300, 275));
        makeSceneDragAware(stage.getScene());
        stage.show();
    }

    public static void initSecondWindow() {
        Stage stage = new Stage();
        stage.setTitle("Window number 2");
        stage.setScene(new Scene(new BorderPane(), 300, 275));
        makeSceneDragAware(stage.getScene());
        stage.show();
    }

    public static void makeSceneDragAware(Scene scene) {
        scene.setOnMouseDragReleased(event -> {
            System.out.println("Released drag");
            if (transferNode != null) {
                ((BorderPane)scene.getRoot()).setCenter(transferNode);
                transferNode = null;

                event.consume();
            }
        });
    }

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

这个问题是setOnMouseDragReleased 在目标窗口上释放时不会被触发。它只会在与拖动节点相同的窗口中触发。

更新: 进行更新以希望获得更多牵引力。我想指出一些使用 JavaFX 的 D&D 功能的代码。

public class Main extends Application {
    private final DataFormat NODE_TYPE = new DataFormat("transferable-node");
    private Node transferNode;

    @Override
    public void start(Stage primaryStage) {
        initFirstWindow();
        initSecondWindow();
    }

    public void initFirstWindow() {
        BorderPane borderPane = new BorderPane();
        Label label = new Label("clickable");
        label.setOnDragDetected(event -> {
            System.out.println("Full drag");
            Dragboard db = label.startDragAndDrop(TransferMode.MOVE);
            ClipboardContent content = new ClipboardContent();

            transferNode = label;
            content.put(NODE_TYPE, "");

            db.setContent(content);
            event.consume();
        });
        borderPane.setCenter(label);

        Stage stage = new Stage();
        stage.setTitle("Window number 1");
        stage.setScene(new Scene(borderPane, 300, 275));
        makeSceneDragAware(stage.getScene());
        stage.show();
    }

    public void initSecondWindow() {
        Stage stage = new Stage();
        stage.setTitle("Window number 2");
        stage.setScene(new Scene(new BorderPane(), 300, 275));
        makeSceneDragAware(stage.getScene());
        stage.show();
    }

    public void makeSceneDragAware(Scene scene) {
        scene.setOnDragOver(event -> {
            event.acceptTransferModes(TransferMode.ANY);
            event.consume();
        });
        scene.setOnDragDropped(event -> {
            if (transferNode != null) {
                ((BorderPane)scene.getRoot()).setCenter(transferNode);
                transferNode = null;

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

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

此代码在技术上可以工作并满足在两个窗口之间移动节点的目标,但是它对我不起作用,因为我不希望任何拖动的元素与外部程序进行拖动交互。使用 D&D 还将停止触发我的应用程序其他部分所需的 setOnMouseDragged 事件。

【问题讨论】:

  • @kleopatra 我已经编辑了问题以添加一些代码。希望这有助于展示我正在尝试做的事情。
  • 我不知道我是否真正理解这个问题。鼠标处理程序在您的示例中起作用。
  • 我的猜测是操作系统具有控制权,因为您正在操作系统级别上执行鼠标事件。
  • hmm ... 本来期望 fullDrag 和处理 mouseDragEvents 会成功(但不会)。投票重新开放。
  • 不相关:不要使用静态范围..

标签: java javafx drag-and-drop window mouseevent


【解决方案1】:

所以我已经设法通过以下代码实现了目标。

public class Main extends Application {
    private Node transferNode;
    private final ArrayList<Stage> stageList = new ArrayList<>();

    @Override
    public void start(Stage primaryStage) {
        initFirstWindow();
        initSecondWindow();
    }

    public void initFirstWindow() {
        BorderPane borderPane = new BorderPane();
        Label label = new Label("clickable");
        label.setOnDragDetected(event -> {
            label.startFullDrag();
            transferNode = label;
        });

        label.setOnMouseReleased(event -> {
            Point point = MouseInfo.getPointerInfo().getLocation().getLocation();
            Stage stage = windowUnderPoint(point);
            if (stage != null) {
                MouseDragEvent mouseEvent = new MouseDragEvent(
                        MouseDragEvent.MOUSE_DRAG_RELEASED, 0, 0, point.getX(), point.getY(),
                        MouseButton.PRIMARY, 1,
                        false, false, false, false, false, false, false,
                        false, false, new PickResult(stage, point.getX(), point.getY()), label);
                stage.fireEvent(mouseEvent);
            }
        });

        borderPane.setCenter(label);

        Stage stage = new Stage();
        stage.setTitle("Window number 1");
        stage.setScene(new Scene(borderPane, 300, 275));
        stage.setX(400);
        makeStageDragAware(stage);
        stage.show();
        stageList.add(stage);
    }

    public void initSecondWindow() {
        Stage stage = new Stage();
        stage.setTitle("Window number 2");
        stage.setScene(new Scene(new BorderPane(), 300, 275));
        stage.setX(800);
        makeStageDragAware(stage);
        stage.show();
        stageList.add(stage);
    }

    public void makeStageDragAware(Stage stage) {
        stage.addEventHandler(MouseDragEvent.MOUSE_DRAG_RELEASED, event -> {
            if (transferNode != null && transferNode.getScene().getWindow() != stage) {
                ((BorderPane) stage.getScene().getRoot()).setCenter(transferNode);
                transferNode = null;
                event.consume();
            }
        });
    }

    public Stage windowUnderPoint(Point point) {
        for (Stage stage : stageList) {
            if (inRange(stage.getX(), stage.getX() + stage.getWidth(), point.getX()) &&
                    inRange(stage.getY(), stage.getY() + stage.getHeight(), point.getY())) {
                return stage;
            }
        }
        return null;
    }

    public boolean inRange(double low, double high, double number) {
        return (number >= low && number <= high);
    }

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

基本上,当拖动节点被释放时,它会获取当前鼠标相对于显示器的坐标,并检查其下是否存在任何已知/注册的阶段。如果找到有效阶段,则会触发阶段MOUSE_DRAG_RELEASED 事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-27
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    • 2021-01-18
    • 2014-03-19
    • 2013-12-15
    • 2014-11-14
    相关资源
    最近更新 更多