0.引子
通常一個TreeNode (DefaultMutableTreeNode)如果沒有子結點,它的節點顯示為不可展開的節點,有時候我們希望即使該節點暫時沒有裝載子結點仍然顯示為可展開的節點(如圖
)。比如,當加載子結點比較耗時或者需要動態刷新,可以延時加載子結點,即在展開節點的時候再去裝載子結點。
1.由來及解決方案
該屬性取決于,DefaultTreeModel的isLeaf方法?
通常一個TreeNode (DefaultMutableTreeNode)如果沒有子結點,它的節點顯示為不可展開的節點,有時候我們希望即使該節點暫時沒有裝載子結點仍然顯示為可展開的節點(如圖

1.由來及解決方案
該屬性取決于,DefaultTreeModel的isLeaf方法?
??? /** * Returns whether the specified node is a leaf node. * The way the test is performed depends on the * <code>askAllowsChildren</code> setting. * * @param node the node to check * @return true if the node is a leaf node * * @see #asksAllowsChildren * @see TreeModel#isLeaf */ publicboolean isLeaf(Object node) { if(asksAllowsChildren) return !((TreeNode)node).getAllowsChildren(); return ((TreeNode)node).isLeaf(); }而asksAllowsChildren由方法setAsksAllowsChildren設定
??? /** * Sets whether or not to test leafness by asking getAllowsChildren() * or isLeaf() to the TreeNodes. If newvalue is true, getAllowsChildren() * is messaged, otherwise isLeaf() is messaged. */ publicvoid setAsksAllowsChildren(boolean newValue) { asksAllowsChildren = newValue; }注意,在setRoot時可以只設定一次
?????? model.setRoot(root); /* * Since nodes are added dynamically in this application, the only true * leaf nodes are nodes that don't allow children to be added. (By * default, askAllowsChildren is false and all nodes without children * are considered to be leaves.) * * But there's a complication: when the tree structure changes, JTree * pre-expands the root node unless it's a leaf. To avoid having the * root pre-expanded, we set askAllowsChildren *after* assigning the * new root. */ model.setAsksAllowsChildren(true);
而在調用model.nodeStructureChanged(node)前后要分別設置為false和true。這是因為nodeStructureChanged會自動的試圖展開節點node,如果isLeaf返回為false。試想,asksAllowsChildren返回true,則一個結點即使沒有子結點,只要設置了allowsChildren,對應的treeNodeModel的isLeaf就會返回true。然而當自動展開節點的時候發現并沒有子結點,當然就會把圖標去掉了。而先把asksAllowsChildren設為false,就不會去試圖展開該節點,然后設為true,該節點就會顯示為
。???
??? /** * Determines whether or not this node is allowed to have children. * If <code>allows</code> is false, all of this node's children are * removed. * <p> * Note: By default, a node allows children. * * @param allows true if this node is allowed to have children */ publicvoid setAllowsChildren(boolean allows) { if (allows != allowsChildren) { allowsChildren = allows; if (!allowsChildren) { removeAllChildren(); } } }
node.removeAllChildren(); DefaultTreeModel model = (DefaultTreeModel) cardTreeView.getModel(); /* * To avoid having JTree re-expand the root node, we disable * ask-allows-children when we notify JTree about the new node * structure. */ model.setAsksAllowsChildren(false); model.nodeStructureChanged(node); model.setAsksAllowsChildren(true);