3 Replies Latest reply: Apr 17, 2013 3:45 AM by bouye RSS

    [javafx] Drag and Drop  treeview

    1003268
      Hi all,

      Sorry, but i speak english like a spanish cow ( thank Bing translator )

      move "b1" to "a" (for example) in a treeview
      ==========treeview :
      -a
      --a1
      --a2
      -b
      --b1
      --b2
      -c
      --c1
      --C2
      ==========code:
      tree.setOnDragDetected...
      tree.setOnDragOver...
      tree.setOnDragDropped ( new EventHandler<DragEvent>() {
      @Override public void handle(DragEvent event) {
      Dragboard db=event.getDragboard();
      boolean success=false;
      if ( event.getDragboard().hasString() ) {
      System.out.println("move "+db.getString());
      *???? How to move to the node pointed to by the cursor ????*
      success=true;
      }
      event.setDropCompleted(success);
      event.consume();
      }
      });

      I know take "b1" ( db.getString() ), but
      how know that the cursor points to "a", "a1, "a2"...
      at the time of dropped ?

      Thanks in advance
        • 1. Re: [javafx] Drag and Drop  treeview
          993317
          Hi, you need to have that implementation in the TreeCell.
          Refer to this: https://gist.github.com/andytill/4009620
          • 2. Re: [javafx] Drag and Drop  treeview
            1003268
            Thank you very much
            it remains for me to understand and apply to my needs
            • 3. Re: [javafx] Drag and Drop  treeview
              bouye
              As posted on Developpez, here's a small working example:
              /*
               * To change this template, choose Tools | Templates
               * and open the template in the editor.
               */
              package test;
              
              import javafx.application.Application;
              import javafx.event.EventHandler;
              import javafx.scene.Scene;
              import javafx.scene.control.TreeCell;
              import javafx.scene.control.TreeItem;
              import javafx.scene.control.TreeView;
              import javafx.scene.control.TreeViewBuilder;
              import javafx.scene.input.ClipboardContent;
              import javafx.scene.input.DataFormat;
              import javafx.scene.input.DragEvent;
              import javafx.scene.input.Dragboard;
              import javafx.scene.input.MouseEvent;
              import javafx.scene.input.TransferMode;
              import javafx.scene.layout.AnchorPane;
              import javafx.scene.layout.AnchorPaneBuilder;
              import javafx.stage.Stage;
              import javafx.util.Callback;
              
              /**
               *
               * @author fabriceb
               */
              public class Main extends Application {
              
                  /**
                   *
                   * @author fabriceb
                   */
                  public class DnDCell extends TreeCell<Integer> {
                      
                      private TreeView<Integer> parentTree;
                      
                      public DnDCell(final TreeView<Integer> parentTree) {
                          this.parentTree = parentTree;
                          // ON SOURCE NODE.
                          setOnDragDetected(new EventHandler<MouseEvent>() {
                              @Override
                              public void handle(MouseEvent event) {
                                  System.out.println("Drag detected on " + item);
                                  if (item == null) {
                                      return;
                                  }
                                  Dragboard dragBoard = startDragAndDrop(TransferMode.MOVE);
                                  ClipboardContent content = new ClipboardContent();
                                  content.put(DataFormat.PLAIN_TEXT, item.toString());
                                  dragBoard.setContent(content);
                                  event.consume();
                              }
                          });
                          setOnDragDone(new EventHandler<DragEvent>() {
                              @Override
                              public void handle(DragEvent dragEvent) {
                                  System.out.println("Drag done on " + item);
                                  dragEvent.consume();
                              }
                          });
                          // ON TARGET NODE.
              //            setOnDragEntered(new EventHandler<DragEvent>() {
              //                @Override
              //                public void handle(DragEvent dragEvent) {
              //                    System.out.println("Drag entered on " + item);
              //                    dragEvent.consume();
              //                }
              //            });        
                          setOnDragOver(new EventHandler<DragEvent>() {
                              @Override
                              public void handle(DragEvent dragEvent) {
                                  System.out.println("Drag over on " + item);
                                  if (dragEvent.getDragboard().hasString()) {
                                      int valueToMove = Integer.parseInt(dragEvent.getDragboard().getString());
                                      if (valueToMove != item) {
                                          // We accept the transfer!!!!!
                                          dragEvent.acceptTransferModes(TransferMode.MOVE);
                                      }
                                  }
                                  dragEvent.consume();
                              }
                          });
              //            setOnDragExited(new EventHandler<DragEvent>() {
              //                @Override
              //                public void handle(DragEvent dragEvent) {
              //                    System.out.println("Drag exited on " + item);
              //                    dragEvent.consume();
              //                }
              //            });        
                          setOnDragDropped(new EventHandler<DragEvent>() {
                              @Override
                              public void handle(DragEvent dragEvent) {
                                  System.out.println("Drag dropped on " + item);
                                  int valueToMove = Integer.parseInt(dragEvent.getDragboard().getString());
                                  TreeItem<Integer> itemToMove = search(parentTree.getRoot(), valueToMove);
                                  TreeItem<Integer> newParent = search(parentTree.getRoot(), item);
                                  // Remove from former parent.
                                  itemToMove.getParent().getChildren().remove(itemToMove);
                                  // Add to new parent.
                                  newParent.getChildren().add(itemToMove);
                                  newParent.setExpanded(true);
                                  dragEvent.consume();
                              }
                          });
                      }
                      
                      private TreeItem<Integer> search(final TreeItem<Integer> currentNode, final int valueToSearch) {
                          TreeItem<Integer> result = null;
                          if (currentNode.getValue() == valueToSearch) {
                              result = currentNode;
                          } else if (!currentNode.isLeaf()) {
                              for (TreeItem<Integer> child : currentNode.getChildren()) {
                                  result = search(child, valueToSearch);
                                  if (result != null) {
                                      break;
                                  }
                              }
                          }
                          return result;
                      }
                      private Integer item;
                      
                      @Override
                      protected void updateItem(Integer item, boolean empty) {
                          super.updateItem(item, empty);
                          this.item = item;
                          String text = (item == null) ? null : item.toString();
                          setText(text);
                      }
                  }
                  
                  @Override
                  public void start(Stage primaryStage) {
                      TreeItem<Integer> treeRoot = new TreeItem(0);
                      treeRoot.getChildren().add(new TreeItem(1));
                      treeRoot.getChildren().add(new TreeItem(2));
                      treeRoot.getChildren().add(new TreeItem(3));
                      TreeView<Integer> treeView = TreeViewBuilder.<Integer>create().root(treeRoot).build();
                      treeView.setCellFactory(new Callback<TreeView<Integer>, TreeCell<Integer>>() {
                          @Override
                          public TreeCell call(TreeView<Integer> param) {
                              return new DnDCell(param);
                          }
                      });
                      AnchorPane.setTopAnchor(treeView, 0d);
                      AnchorPane.setRightAnchor(treeView, 0d);
                      AnchorPane.setBottomAnchor(treeView, 0d);
                      AnchorPane.setLeftAnchor(treeView, 0d);
                      //
                      AnchorPane root = AnchorPaneBuilder.create().children(treeView).build();
                      Scene scene = new Scene(root, 300, 250);
                      //
                      primaryStage.setTitle("Hello World!");
                      primaryStage.setScene(scene);
                      primaryStage.show();
                  }
              
                  /**
                   * The main() method is ignored in correctly deployed JavaFX 
                   * application. main() serves only as fallback in case the 
                   * application can not be launched through deployment artifacts,
                   * e.g., in IDEs with limited FX support. NetBeans ignores main().
                   * @param args the command line arguments
                   */
                  public static void main(String[] args) {
                      launch(args);
                  }
              }
              More tests need to be added though:
              - to prevent the root from being moved.
              - and more generally, to prevent an ancestor node from being dropped on one of its descendant nodes.

              And need to expand to use some more complex data types than int/Integer. I haven't much looked how one could transfer JVM object using JavaFX DnD, it was possible in Swing with the proper flavor.

              Edited by: bouye on Apr 17, 2013 7:44 PM - spelling