Peter Penzov
Peter Penzov

Reputation: 1764

How to switch TabPanes places with mouse drag

I would like to extend this post of TabPanes implementation.

I'm interested is it somehow possible to drag TabPanes with the mouse in order to change the position of the TabPane with mouse drag. Basic explanation how this can be implemented will highly appreciated.

import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;


public class FXSplitTabs extends Application{

    @Override
    public void start(Stage stage) throws Exception {
        stage.setTitle("SplitTabs");
        stage.setWidth(700);
        stage.setHeight(500);

        //Setup Center and Right
        TabPaneWrapper wrapper = new TabPaneWrapper(Orientation.HORIZONTAL, .9);
        TabPane centerPane = new TabPane();
        centerPane.getTabs().addAll(generateTab("Tab 1"),generateTab("Tab 2"), generateTab("Tab 3"), generateTab("Tab N"));

        TabPane rightPane = new TabPane();
        rightPane.getTabs().addAll(generateTab("Tab 1"),generateTab("Tab 2"), generateTab("Tab 3"), generateTab("Tab N"));
        SplitPane.setResizableWithParent(rightPane, false);
        wrapper.addNodes(centerPane, rightPane);

        //Add bottom
        TabPane bottomPane = new TabPane();
        bottomPane.getTabs().addAll(generateTab("Tab 1"),generateTab("Tab 2"), generateTab("Tab 3"), generateTab("Tab N"));
        TabPaneWrapper wrapperBottom = new TabPaneWrapper(Orientation.VERTICAL, .7);
        wrapperBottom.addNodes(wrapper.getNode(), bottomPane);

        //Add left
        TabPane leftPane = new TabPane();
        leftPane.getTabs().addAll(generateTab("Tab 1"),generateTab("Tab 2"), generateTab("Tab 3"), generateTab("Tab N"));
        TabPaneWrapper wrapperleft = new TabPaneWrapper(Orientation.HORIZONTAL, .1);
        wrapperleft.addNodes(leftPane, wrapperBottom.getNode());

        Scene myScene = new Scene(wrapperleft.getNode());
        stage.setScene(myScene);
        stage.sizeToScene();
        stage.show();
    }

    public Tab generateTab(String name){
        Tab result = new Tab(name);
        BorderPane content = new BorderPane();
        TextArea text = new TextArea();
        content.setCenter(text);
        result.setContent(content);
        return result;
    }

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

    public static class TabPaneWrapper{
        SplitPane split;

        public TabPaneWrapper(Orientation o, double splitLocation){
            split = new SplitPane();

            //Change the CSS (uncomment if using an external css)
            //split.getStylesheets().add("test.css");

            split.setOrientation(o);
            split.setDividerPosition(0, splitLocation);
        }

        public void addNodes(final Node node1, final Node node2){
            //Add to the split pane
            split.getItems().addAll(node1, node2);
        }

        public Parent getNode(){
            return split;
        }
    }

}

enter image description here

Upvotes: 1

Views: 1538

Answers (1)

Nick Rippe
Nick Rippe

Reputation: 6475

I'd recommend adding an onDragDetected listener and a onMouseDragReleased listener to all your TabPanes.

    TabPaneDrag drag = new TabPaneDrag();
    ...
    centerPane.setOnDragDetected(drag);
    centerPane.setOnMouseDragReleased(drag);
    ...
    rightPane.setOnDragDetected(drag);
    rightPane.setOnMouseDragReleased(drag);

In your listener, you can keep track of what pane started the drag and which pane ended the drag (Then switch them if necessary). Here's a quick example (mind you, there's some special cases and and kinks and such I didn't bother with - And findWrapper() is a method that returns the TabPaneWrapper containing the TabPane):

public class TabPaneDrag implements EventHandler<MouseEvent>{
    Node start;
    Node end;

    @Override
    public void handle(MouseEvent arg0) {
        if(arg0.getEventType().equals(MouseEvent.DRAG_DETECTED)){
            start = (Node)arg0.getSource();
            start.startFullDrag(); //allows events to fire on nodes besides source
        } else if(arg0.getEventType().equals(MouseDragEvent.MOUSE_DRAG_RELEASED)){
            end = (Node)arg0.getSource();
            if(end != start){
                ObservableList<Node> startWrapper = findWrapper(start).split.getItems();
                ObservableList<Node> endWrapper = findWrapper(end).split.getItems();
                int startIndex = startWrapper.indexOf(start);
                int endIndex = endWrapper.indexOf(end);

                // Remove/Add  the TabbedPanes to the new order
                endWrapper.remove(endIndex);
                startWrapper.remove(startIndex);

                startWrapper.add(startIndex, end);
                endWrapper.add(endIndex, start);

            }
            start = null;
            end = null;
        }
    }
}

Upvotes: 1

Related Questions