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

801 views Asked by At

I'm using SplitPane in JavaFx to split two nodes with a divider. I am looking for a way to differentiate between two cases. One case when the divider is moving responsively on screen width changes, second case is when I'm using the mouse to drag the divider to a certain position. I need to add a listener to the divider when it's dragged using the mouse. How can I do that?

1

There are 1 answers

2
VGR On BEST ANSWER

What you need is a way to know when the change in divider position is the result of a window resize. Or, more formally, a Scene resize.

You can set a flag whenever the Scene is doing a layout, using addPreLayoutPulseListener, then clear that flag at the end of resize event processing using Platform.runLater. While that flag is true, you can assume any change in SplitPane divider position was due to the Scene layout, not due to user actions.

Here’s an example:

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

Note that addPreLayoutPulseListener was added as of JavaFX 9, and isn’t available in older versions.

Java 8

For older versions of JavaFX, you can accomplish the same thing by overriding the layoutChildren() method of your Scene’s root:

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