Hi list, I am trying to implement drag&drop in a tree view. I actually did it. It works. In 1/3rd of the times. Otherwise there are times when relevant events do not arrive, and events kick in from nowhere.
Specifically I don't see the dragDone event to fire, although I call setDropCompleted(true) in the dragDropped event. If I do hand testing, I just can't see much correlation between events arriving and the mouse movements I do. dragDropped events came out of nowhere, some cells receive dragEnter/Exit/Over event, some not, the event source is set to misterious values. This is how I test (see https://github.com/magwas/zenta3/blob/master/ui/src/test/java/org/rulez/demokracia/zenta3/editor/DragAndDropTest.java for full code): @Test public void when_the_drag_is_dropped_the_element_is_moved( final FxRobot robot ) { final ZentaTreeCell startCell = findCellFor(newElement); robot.drag(startCell); final ZentaTreeCell targetCell = findCellFor(thing); final int targetIndex = targetCell.getIndex(); robot.moveTo(targetCell); robot.dropTo(targetCell); WaitForAsyncUtils.waitForFxEvents(); final ZentaTreeCell endCell = findCellFor(newElement); assertEquals(targetIndex + 1, endCell.getIndex()); } And these are the relevant lines of my TreeCell implementation ( https://github.com/magwas/zenta3/blob/master/ui/src/main/java/org/rulez/demokracia/zenta3/editor/tree/ZentaTreeCell.java for full code): public class ZentaTreeCell extends TreeCell<ZentaElement> { public static final DataFormat ZENTA_FORMAT = new DataFormat("Zenta Elements"); private final TreeView<ZentaElement> treeView; public ZentaTreeCell(final TreeView<ZentaElement> view) { super(); treeView = view; setOnDragDetected((e) -> dragDetected(e)); setOnDragEntered((e) -> dragEntered(e)); setOnDragOver((e) -> dragOver(e)); setOnDragExited((e) -> dragExited(e)); setOnDragDropped((e) -> dragDropped(e)); setOnDragDone((e) -> dragDone(e)); } private void dragDone(final DragEvent e) { System.out.println("done\n\tat " + this + "\n\t event: " + e); } private void dragDropped(final DragEvent e) { System.out.println("dropped\n\tat " + this + "\n\t event: " + e); e.setDropCompleted(true); e.getDragboard().clear(); e.consume(); getStyleClass().remove("dragtarget"); final ZentaTreeCell gestureSource = (ZentaTreeCell) e.getGestureSource(); final ZentaTreeCell gestureTarget = (ZentaTreeCell) e.getGestureTarget(); final TreeItem<ZentaElement> draggedItem = gestureSource.getTreeItem(); final TreeItem<ZentaElement> draggedItemParent = draggedItem.getParent(); final TreeItem<ZentaElement> droppeditem = gestureTarget.getTreeItem(); final TreeItem<ZentaElement> droppedItemParent = droppeditem.getParent(); final int indexInParent = droppedItemParent.getChildren().indexOf(droppeditem); draggedItemParent.getChildren().remove(draggedItem); droppedItemParent.getChildren().add(indexInParent + 1, draggedItem); treeView.getSelectionModel().select(draggedItem); } private void dragOver(final DragEvent e) { System.out.println("over\n\tat " + this + "\n\t event: " + e); e.acceptTransferModes(TransferMode.MOVE); e.consume(); } private void dragEntered(final DragEvent e) { System.out.println("entered\n\tat " + this + "\n\t event: " + e); getStyleClass().add("dragtarget"); e.consume(); } private void dragExited(final DragEvent e) { System.out.println("exited\n\tat " + this + "\n\t event: " + e); getStyleClass().remove("dragtarget"); e.consume(); } public void dragDetected(final MouseEvent e) { System.out.println("detected\n\tat " + this + "\n\t event: " + e); System.out.println("dragDetected"); final Dragboard dragBoard = startDragAndDrop(TransferMode.MOVE); final Map<DataFormat, Object> map = new HashMap<>(); final ZentaElement item = getItem(); map.put(ZENTA_FORMAT, item); System.out.println("item: " + item); dragBoard.setContent(map); e.consume(); } @Override public void updateItem(final ZentaElement item, final boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); final ZentaElement currentItem = getItem(); if (null != currentItem) currentItem.removePropertyChangeListener((e) -> propertyChanged(e)); setItem(null); } else { setText(item.getName()); item.addPropertyChangeListener((e) -> propertyChanged(e)); } setItem(item); } private void propertyChanged(final PropertyChangeEvent e) { if (Folder.CHILDREN_PROPERTY.contentEquals(e.getPropertyName())) { final TreeItem<ZentaElement> item = new ZentaTreeItem((ZentaElement) e.getNewValue()); final TreeItem<ZentaElement> folderItem = getTreeItem(); if (!(folderItem instanceof ZentaTreeItem)) return; final ZentaTreeItem folderCell = (ZentaTreeItem) folderItem; folderCell.getChildren().add(item); } } } I guess I am missing something here, but after reading all the documentation about drag&drop, I don't see what.