Why isn't my JTree updating when the TreeModel

2019-07-04 01:53发布

问题:

I am using a DefaultTreeModel populated with an override of DefaultMutableTreeNode which supports optionally changing the display string of a node in a tree. As shown in the code below, in my form I populate the tree with new nodes by creating them in a separate class and then passing them in via a wrapper class for my main data type. The procedure there is to create a new overridden DefaultMutableTreeNode, add children to it (each AccessPoint is represented by a node with several child nodes), then store it for later use in the UI.

The first time I add a node this way, it works beautifully. Any subsequent node added with the following code is in fact stored in the DefaultTreeModel, but the JTree is not being updated with the new nodes.

Why is it that the JTree doesn't get populated after the first child is added?

private void populateAccessPointTreeModel(AccessPointDataWrapper wrapper) {
    //the pre-created DefaultMutableTreeNode subclass instance is
    // stored in the wrapper
    DefaultMutableTreeNode accessPointNode =
            wrapper.getAccessPointTreeNode();
    //this line updates the accessPointTree with the new node (I've looked at the
    // value in debug mode, and it does in fact add the node
    ((DefaultMutableTreeNode) accessPointTree.getRoot()).add(accessPointNode);
    //unrelated logic happens down here...
}

I can include the code where I create the node if necessary, but I don't think it is the issue.

回答1:

The problem is that DefaultMutableTreeNode does not inform the DefaultTreeModel that its children were updated. To do this you'll either want to call the appropriate method in the table model (nodesChanged or similar) or (preferably) use the DefaultTreeModel.insertNodesInto method.

DefaultTreeModel model = (DefaultTreeModel)accessPointTree.getModel();
DefaultMutableTreeNode root = model.getRoot();
model.insertNodeInto(accessPointNode, root, root.getChildCount());


回答2:

Quite likely you are having some threading issue. Your JTree is updated is some thread, but the important copy of the JTree, the one that is displayed in the Swing event dispatch thread (EDT), knows nothing of those changes.

If this is the case, you have to update the JTree in the Swing EDT using:

SwingUtilities.invokeLater(new Runnable() {
  @Override public void run() { ... update jTree here }
});

I don't know about JTree... maybe it's the TreeModel you have to update in the Swing EDT.