Subhra Jyoti Lahiri Subhra Jyoti Lahiri - 1 month ago 21
Java Question

I am new to JavaFX. I want help on how to make a TreeView node Draggable and Droppable

I know this question has been asked a multiple times, but I was unable to get help from any of the article.

My Main.FXML is


<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<TreeView fx:id="treeView" layoutX="51.0" layoutY="24.0" onContextMenuRequested="#mouseClick" onMouseClicked="#mouseClick" prefHeight="352.0" prefWidth="493.0" />
</children>
</AnchorPane>


My Controller.java is

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.MouseEvent;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable
{
@FXML TreeView<String> treeView;

@Override
public void initialize(URL location, ResourceBundle resources)
{
TreeItem<String> root = new TreeItem<>("root");

TreeItem<String> nodeA = new TreeItem<>("nodeA");
TreeItem<String> nodeB = new TreeItem<>("nodeB");
TreeItem<String> nodeC = new TreeItem<>("nodeC");

root.getChildren().add(nodeA);
root.getChildren().add(nodeB);
root.getChildren().add(nodeC);

treeView.setRoot(root);

root.setExpanded(true);
}

@FXML
private void mouseClick(MouseEvent mouseEvent)
{
TreeItem<String> item = treeView.getSelectionModel().getSelectedItem();
System.out.println(item.getValue());
}
}


My Main.java is

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}


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


I have seen article that teaches how to add the Drag and Drop feature to TreeItem via TreeCell by adding Cell Property. But the processes were quiet complicated and I being a layman to JavaFX was unable to understand those.

So, it will be quite helpful if anyone can help me out with this.

Thanks in Advance.

Answer

Add in your Controller code responsible for setting a custom cell factory, that will attach handlers to Drag/MouseEvents.

treeView.setCellFactory(param -> {
    // creating cell from deafult factory
    TreeCell<String> treeCell = TextFieldTreeCell.forTreeView().call(param);
    // setting handlers
    treeCell.setOnDragDetected(this::onDragDetected);
    treeCell.setOnDragOver(this::onDragOver);
    treeCell.setOnDragDropped(this::onDragDropped);
    return treeCell;
});

Basic handlers taken from DragEvent javadoc page:

private void onDragDetected(MouseEvent event) {
    TreeCell<String> source = (TreeCell<String>) event.getSource();
    Dragboard db = source.startDragAndDrop(TransferMode.ANY);
    ClipboardContent content = new ClipboardContent();
    content.putString(source.getItem());
    db.setContent(content);
    event.consume();
}

private void onDragOver(DragEvent dragEvent) {
    Dragboard db = dragEvent.getDragboard();
    if (db.hasString()) {
        dragEvent.acceptTransferModes(TransferMode.COPY);
    }
    dragEvent.consume();
}

private void onDragDropped(DragEvent event) {
    Dragboard db = event.getDragboard();
    boolean success = false;
    if (db.hasString()) {
        System.out.println("Dropped: " + db.getString());
        success = true;
    }
    event.setDropCompleted(success);
    event.consume();
}
Comments