Removing nodes in JTree at different levels of nesting

I implement drag and drop in JTree. I want the user to be able to delete node at different levels of the tree.

In the example below, imagine a user inserting an element between "grandchild A2" and "child C":

root child A grandchild A1 grandchild A2 child C grandchild C1 

Now there are two options:

  • Add a new grandson to "child A" which will be "grandchild A3", or
  • Insert a new โ€œchild Bโ€ between โ€œchild Aโ€ and โ€œchild Bโ€.

In SWT, this is possible by moving the node a bit in the vertical direction. The horizontal line indicator will show at what level of nesting the node tree is installed.

Is this even possible in Swing? I can not find information about this. The line indicator in Swing is always displayed at only one level.

And if not, is there a workaround?

+4
source share
2 answers

I donโ€™t find it possible to perform exactly the behavior you want using the Swing built-in drag and drop.

A potential workaround is to set the drop mode to ON_OR_INSERT as follows: tree.setDropMode(DropMode.ON_OR_INSERT);

ON_OR_INSERT supports resetting either ON a node directly or between nodes. The INSERT part supports resetting between "A" and "B". You can then allow users to add a new grandson "A" after "A3" in one of two ways (or both):

  • Interpret drops directly on โ€œAโ€ as adding an element as the last child of โ€œAโ€
  • Interpret the fall on a node as adding an element after a node (this is problematic if the node is not a leaf, since the expected behavior is to add the element to the child element)

If you need exactly the behavior you are describing, you will probably need to write a custom DropTarget for the table and draw the desired effects (a line showing where the drop will occur). I would recommend avoiding this, if at all possible.

+2
source

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.).

+1
source

Source: https://habr.com/ru/post/1337775/


All Articles