How to drag a JavaFX node and detect a drop event outside the JavaFX Windows?


Question

I'm implementing a TabPane that can be detached from the JavaFX window. When the tab pane is dragged outside of the window where it came from, I would like a new window to be created and the tab to be placed in that window.

I already implemented some methods using drag gestures to drag the tab between existing windows. However, I am not able to receive any mouse events or drag events when the mouse is moved outside of JavaFX scenes. Is this something possible?

1
1
10/28/2014 2:18:16 PM

Accepted Answer

You can listen for a mouse released event on the appropriate node (e.g. the tab's graphic). Check the screen coordinates using MouseEvent.getScreenX() and MouseEvent.getScreenY() and see if they lie outside the current window. If they do, create a new window, scene, and tab pane; remove the tab from the current tab pane and place it in the new one.

Here's a basic example with no frills (e.g. no user hints as to the fact that dragging is occuring), but it will give you the idea:

import javafx.application.Application;
import javafx.collections.ListChangeListener.Change;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.stage.Window;

public class DetachableTabExample extends Application {

    private int tabCount = 0 ;

    @Override
    public void start(Stage primaryStage) {
        TabPane tabPane = new TabPane();
        Button newTabButton = new Button("New Tab");
        newTabButton.setOnAction(event -> {
            Tab tab = new Tab();
            Label tabLabel = new Label("Tab "+(++tabCount));
            tab.setGraphic(tabLabel);
            tab.setContent(new TextArea());
            tabPane.getTabs().add(tab);

            tabLabel.setOnMouseReleased(me -> {
                Point2D mouseLoc = new Point2D(me.getScreenX(), me.getScreenY());
                Window window = tabPane.getScene().getWindow();
                Rectangle2D windowBounds 
                    = new Rectangle2D(window.getX(), window.getY(),
                                      window.getWidth(), window.getHeight());
                if (! windowBounds.contains(mouseLoc)) {
                    tabPane.getTabs().remove(tab);
                    Stage newStage = new Stage();
                    TabPane newTabPane = new TabPane();
                    newTabPane.getTabs().add(tab);
                    Scene scene = new Scene(new BorderPane(newTabPane));
                    newStage.setScene(scene);
                    newStage.setX(me.getScreenX());
                    newStage.setY(me.getScreenY());
                    newStage.setWidth(window.getWidth());
                    newStage.setHeight(window.getHeight());
                    newStage.show();
                }
            });

        });


        BorderPane root = new BorderPane(tabPane, newTabButton, null, null, null);
        Scene scene = new Scene(root, 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
3
10/28/2014 2:47:49 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon