如何在 JavaFX 中的 SplitPane Divider 上检测鼠标拖动事件

How to detect mouse-dragged event on SplitPane Divider in JavaFX

我在 JavaFx 中使用 SplitPane 用分隔符拆分两个节点。我正在寻找一种方法来区分两种情况。一种情况是当分隔线响应屏幕宽度变化而移动时,第二种情况是当我使用鼠标将分隔线拖动到某个位置时。使用鼠标拖动时,我需要向分隔线添加一个侦听器。我该怎么做?

您需要一种方法来了解分隔符位置的变化何时是 window 调整大小的结果。或者,更正式地说,场景调整大小。

您可以在场景进行布局时设置标志,使用addPreLayoutPulseListener, then clear that flag at the end of resize event processing using Platform.runLater。虽然该标志为真,但您可以假设 SplitPane 分隔线位置的任何变化都是由于场景布局造成的,而不是由于用户操作造成的。

举个例子:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.BorderPane;

public class DividerListenerTest
extends Application {
    private boolean windowResizing;

    @Override
    public void start(Stage stage) {
        Label left = new Label("Left");
        left.setMinSize(1, 1);
        left.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        left.setPadding(new Insets(200));

        Label right = new Label("Right");
        right.setMinSize(1, 1);
        right.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        right.setPadding(new Insets(200));

        SplitPane splitPane = new SplitPane(left, right);

        splitPane.getDividers().get(0).positionProperty().addListener(
            (o, oldPos, newPos) -> dividerResized(oldPos, newPos));

        Scene scene = new Scene(new BorderPane(splitPane));
        scene.addPreLayoutPulseListener(() -> {
            windowResizing = true;
            Platform.runLater(() -> {
                windowResizing = false;
            });
        });

        stage.setScene(scene);
        stage.setTitle("Divider Listener Test");
        stage.show();
    }

    private void dividerResized(Number oldPos,
                                Number newPos) {
        if (windowResizing) {
            return;
        }

        System.out.println("User moved divider position to " + newPos);
    }

    public static class Main {
        public static void main(String[] args) {
            Application.launch(DividerListenerTest.class, args);
        }
    }
}

请注意,addPreLayoutPulseListener 是从 JavaFX 9 开始添加的,在旧版本中不可用。

Java 8

对于旧版本的 JavaFX,您可以通过重写场景根的 layoutChildren() 方法来完成同样的事情:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.BorderPane;

public class DividerListenerTest
extends Application {
    private boolean windowResizing;

    @Override
    public void start(Stage stage) {
        Label left = new Label("Left");
        left.setMinSize(1, 1);
        left.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        left.setPadding(new Insets(200));

        Label right = new Label("Right");
        right.setMinSize(1, 1);
        right.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        right.setPadding(new Insets(200));

        SplitPane splitPane = new SplitPane(left, right);

        splitPane.getDividers().get(0).positionProperty().addListener(
            (o, oldPos, newPos) -> dividerResized(oldPos, newPos));

        Scene scene = new Scene(new BorderPane(splitPane) {
            @Override
            protected void layoutChildren() {
                windowResizing = true;
                super.layoutChildren();
                Platform.runLater(() -> {
                    windowResizing = false;
                });
            }
        });

        stage.setScene(scene);
        stage.setTitle("Divider Listener Test");
        stage.show();
    }

    private void dividerResized(Number oldPos,
                                Number newPos) {
        if (windowResizing) {
            return;
        }

        System.out.println("User moved divider position to " + newPos);
    }
}