This is a java drop location processing error and is difficult to resolve without changing the JDK source. It has not yet been resolved, but there is also a related improvement request with possible impractical workarounds that have been closed since they will not be fixed.
The only way I was able to do this was to add a dummy node as the last child of any node container. This is complicated and adds a line, which may be undesirable, but allows the user to discard the node as the last child of the container.
public class TreeDragAndDrop { private static final int CONTAINER_ROW = 0; private static final int PLACEHOLDER_ROW = 3; private JScrollPane getContent() { JTree tree = new JTree(getTreeModel()) { // Overridden to prevent placeholder selection via the keyboad @Override public void setSelectionInterval(int index0, int index1) { int index = index0; // Probably would use a better check for placeholder row in production // and use a while loop in case the new index is also a placeholder if (index == PLACEHOLDER_ROW) { int currentSelection = getSelectionCount() > 0 ? getSelectionRows()[0] : -1; if (currentSelection < index) { index++; } else { index--; } } super.setSelectionInterval(index, index); } // Overridden to prevent placeholder selection via the mouse @Override public void setSelectionPath(TreePath path) { if (path != null && getRowForPath(path) != PLACEHOLDER_ROW) { super.setSelectionPath(path); } } }; tree.setRootVisible(false); tree.setDragEnabled(true); tree.setDropMode(DropMode.INSERT); tree.setTransferHandler(...); tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); tree.expandRow(CONTAINER_ROW); return new JScrollPane(tree); } protected static TreeModel getTreeModel() { DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root"); DefaultMutableTreeNode a; a = new DefaultMutableTreeNode("A"); root.add(a); a.add(new DefaultMutableTreeNode("X")); a.add(new DefaultMutableTreeNode("Y")); a.add(new DefaultMutableTreeNode("")); // Placeholder node root.add(new DefaultMutableTreeNode("B")); root.add(new DefaultMutableTreeNode("C")); return new DefaultTreeModel(root); } public static void main(String[] args) { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(new TreeDragAndDrop().getContent()); f.setSize(400, 400); f.setLocationRelativeTo(null); f.setVisible(true); } // TransferHandler code omitted }
You might want the custom renderer to change the appearance of placeholder strings (for example, hide the icon, reduce the height (although you cannot make it height 0), etc.).
source share