In my application, I show a JTree on the left side and if the user double clicks on a leaf, the corresponding data is loaded on the right side. At the time of loading this data, I (i) save the existing document (not relevant here), (ii) update the tree to account for any changes that may have happened, (iii) make sure the right node is selected in the tree after updating (i.e. the node the user double-clicked on) and (iv) load the selected node. The application logic works fine, i.e. the correct file is loaded and we therefore know that the correct node is selected in the tree, but visually no node is selected at all after the aforementioned steps.
I am aware of this question but the problem there seems to have been that the tree was not in focus. I have already tried the different remedies suggested in that post but have not been able to solve my problem. (There is also this related forum thread, although the site seems to be down right now. Furthermore, this question seems to be similar on the surface but the problem there stems from OP building a proprietary renderer.)
Please see below my code; I tried to reduce it to a SSCCE but I'm still stuck. My best guess at this time is that the problem has to do with the fact that a completely new TreeModel is created and loaded into the tree every time updateTree
is called and that this somehow makes it impossible to visually select the right node. If this were indeed to be the case, then one potential solution would be to alter the TreeModel instead of re-creating it from scratch but (i) that's less convenient for me and (ii) I believe this presents an interesting problem in its own right.
public class JTree_Problem_SSCCE
extends JFrame
{
private final JTree tree;
public JTree_Problem_SSCCE()
{
super("XYZ");
// Tree to select data
DefaultTreeModel treeModel = getTreeModel();
this.tree = new JTree(treeModel);
// I don't allow the user to select more than one node at a time but I can reproduce the problem with or without this
//TreeSelectionModel tsm = new DefaultTreeSelectionModel();
//tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
//tree.setSelectionModel(tsm);
tree.addMouseListener(new TreeMouseAdapter());
expandAllTreeNodes();
getContentPane().add(tree,BorderLayout.WEST);
setLocation(25,25);
setSize(1700,1000);
setVisible(true);
}
private DefaultTreeModel getTreeModel()
{
DefaultMutableTreeNode n1 = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode n2 = new DefaultMutableTreeNode("Child 1");
DefaultMutableTreeNode n3 = new DefaultMutableTreeNode("Child 2");
n1.add(n2);
n1.add(n3);
return new DefaultTreeModel(n1);
}
private void updateTree(DefaultMutableTreeNode treeNode)
{
DefaultTreeModel dtm = getTreeModel();
tree.setModel(dtm);
expandAllTreeNodes();
// No idea why the below doesn't work visually (the application logic works just fine but no tree node is actually selected)
System.err.println(tree.getExpandsSelectedPaths()); // always returns true (I've seen this to be the problem in other questions)
System.err.println(new TreePath(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode)));
if (treeNode != null)
{
tree.setSelectionPath(new TreePath(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode)));
}
// As recommended in the answers here (https://stackoverflow.com/q/8896678/8031521),
// I have tried the below but to no avail
// tree.requestFocus(); // I have also tried requestFocusInWindow
// SwingUtilities.invokeLater(new Runnable() {
// @Override
// public void run()
// {
// tree.setSelectionPath(new TreePath(((DefaultTreeModel)tree.getModel()).getPathToRoot(treeNode)));
// }
// });
}
private void expandAllTreeNodes()
{
// Expand all the nodes in the tree
// See https://stackoverflow.com/a/15211697/8031521
for (int i = 0; i < tree.getRowCount(); i++)
{
tree.expandRow(i);
}
}
class TreeMouseAdapter
extends MouseAdapter
{
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 2 &&
((DefaultMutableTreeNode)tree.getLastSelectedPathComponent()).isLeaf())
{
// [Before opening the new file, save the old one]
// After saving the old file, make sure the tree is up to date
updateTree((DefaultMutableTreeNode)tree.getLastSelectedPathComponent());
// [Now we open the new file]
}
}
}
}