java JTree更新节点而不折叠
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12249777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JTree update nodes without collapsing
提问by David B
I have a Java SE 7 application that needs to have the JTree
nodes updated. From the tutorial given by Oracle using this thread, there's no given hint on how I could update the label (displayed text of the node on the Tree) on code. Currently I am using DefaultTreeModel
as the model of my JTree
and DefaultMutableTreeNode
as the nodes of the said Tree.
我有一个需要JTree
更新节点的 Java SE 7 应用程序。从 Oracle 使用此线程给出的教程中,没有给出关于如何更新代码标签(树上节点的显示文本)的提示。目前我正在DefaultTreeModel
用作我的模型JTree
和DefaultMutableTreeNode
所述树的节点。
To further detail about the application I am working on, I am developing a chat facility having the contact(s) displayed with their availability status (whether Online, Offline, etc.) per account.
为了进一步详细了解我正在处理的应用程序,我正在开发一个聊天工具,其中显示了每个帐户的联系人及其可用性状态(无论是在线、离线等)。
The question is, how can I update the displayed text of a particular node without (at most) removing it from it's parent and adding it on it's designated index. Like a DefaultMutableTreeNode.setText("<new label>")
?
问题是,如何更新特定节点的显示文本而不(最多)将其从其父节点中删除并将其添加到其指定的索引上。像一个DefaultMutableTreeNode.setText("<new label>")
?
UPDATE : January 20, 2013
更新:2013 年 1 月 20 日
Redefined the question for clarifications.
重新定义问题以进行澄清。
采纳答案by vels4j
May this simple and executable program help you to resolve your issue.
愿这个简单且可执行的程序能帮助您解决问题。
public class JTreeDemo extends JPanel
implements Runnable {
private JTree tree;
private DefaultTreeModel treeModel ;
private Random rnd = new Random();
private List<User> userList;
public JTreeDemo() {
super( );
//Create the nodes.
DefaultMutableTreeNode top =
new DefaultMutableTreeNode("Users");
treeModel = new DefaultTreeModel(top);
createNodes(top);
//Create a tree that allows one selection at a time.
tree = new JTree(treeModel);
tree.getSelectionModel().setSelectionMode
(TreeSelectionModel.SINGLE_TREE_SELECTION);
//Create the scroll pane and add the tree to it.
JScrollPane treeView = new JScrollPane(tree);
//Add the split pane to this panel.
add(treeView);
}
public String getRandomStatus() {
int nextInt = rnd.nextInt(100);
if( nextInt%2==0) {
return "Online";
} else {
return "Offline";
}
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
int nextInt = rnd.nextInt(10);
User user = userList.get(nextInt);
user.setStatus(getRandomStatus());
treeModel.nodeChanged(user);
} catch (InterruptedException ex) {
// handle it if necessary
}
}
}
private class User extends DefaultMutableTreeNode {
public String userName;
public String status;
public User(String name) {
userName = name;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
@Override
public String toString() {
String color = status.equals("Online") ? "Green" : "Red";
return "<html><b color='"+color+"'>"+
userName +"-"+status +"</b></html>";
}
}
private void createNodes(DefaultMutableTreeNode top) {
userList = new ArrayList() ;
for(int i=0;i<10;i++) {
User u1 = new User("User " + (i+1));
u1.setStatus("Online");
top.add(u1);
userList.add(u1);
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TreeDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add content to the window.
JTreeDemo jTreeDemo = new JTreeDemo();
frame.add(jTreeDemo);
frame.pack();
frame.setVisible(true);
// update status randomly
Thread thread = new Thread(jTreeDemo);
thread.start();
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
I've added a Thread to update Status randomly, hope you can modify base on your need.
我添加了一个线程来随机更新状态,希望您可以根据需要进行修改。
Output :
输出 :
Edit:
1. Based on suggestion I've removed reload(node)
and added tree model reload.
编辑:
1. 根据建议,我删除reload(node)
并添加了树模型重新加载。
回答by Lee Meador
Perhaps if you use 'nodeChanged()' instead of 'reload()' you will get the effect you desire.
也许如果您使用 'nodeChanged()' 而不是 'reload()' 您将获得您想要的效果。
There are a bunch of methods on the DefaultTreeModel class that cause various parts of the tree to be changed and redrawn. There are also other methods on DefaultTreeModel that only cause redrawing to take place.
DefaultTreeModel 类上有很多方法可以更改和重绘树的各个部分。DefaultTreeModel 上还有其他方法只会导致重绘发生。
You mentioned 'reload(node)' and commented that it causes the tree to collapse when you call it. 'reload' causes the entire sub-tree to be completely redrawn starting at that node. (But if that node isn't visible, it changes nothing.) That is called a 'structure change'.
您提到了“重新加载(节点)”并评论说它会在您调用它时导致树折叠。'reload' 导致从该节点开始完全重绘整个子树。(但如果该节点不可见,则它不会发生任何变化。)这称为“结构变化”。
'insertNodeInto()' and 'removeNodeFromParent()' modify the tree structure by adding or removing the node and then redrawing.
'insertNodeInto()' 和 'removeNodeFromParent()' 通过添加或删除节点然后重绘来修改树结构。
I think 'nodeChanged()' is the one you need since it just notifies the model that something changed in the node that will cause it to display differently. Perhaps the displayable text is now different than it was. Perhaps you changed the user object in the node. That's when you call 'nodeChanged()' on a node.
我认为 'nodeChanged()' 是您需要的,因为它只是通知模型节点中的某些更改将导致它以不同的方式显示。也许现在可显示的文本与以前不同了。也许您更改了节点中的用户对象。那是当您在节点上调用“nodeChanged()”时。
You should try 'nodeChanged()' in place of the 'reload()' call in your own code that was collapsing and in the example program vels4j provided. This might take care of the problem.
您应该在自己的折叠代码和提供的示例程序 vels4j 中尝试使用 'nodeChanged()' 代替 'reload()' 调用。这可能会解决问题。
Note that there are also two other families of methods on the DefaultTreeModel that are used in other cases:
请注意, DefaultTreeModel 上还有另外两个方法系列可用于其他情况:
These methods work with the tree nodes and use the tree path to define where the change took place. They do not change the data structures underlying the tree but notify the model that something changed so it can notify the listeners that actually redraw things or otherwise respond to changes.
这些方法与树节点一起工作,并使用树路径来定义发生更改的位置。它们不会更改树下的数据结构,而是通知模型发生了某些更改,以便它可以通知实际重绘事物或以其他方式响应更改的侦听器。
nodesWereInserted()
nodesWereRemovde()
nodesChanged()
nodeStructureChanged()
nodesWereInserted()
nodesWereRemovde()
nodesChanged()
nodeStructureChanged()
There are also a set of fire...()
methods that are used internally to the DefaultTreeModel and any sub-classes you may create. They merely notify any listeners that something changed. Notice that they are protected.
还有一组fire...()
在 DefaultTreeModel 和您可能创建的任何子类内部使用的方法。他们只是通知任何听众发生了一些变化。请注意,它们受到保护。
回答by Sergiy Medvynskyy
It's easy if nodes contains objects which are unique in the tree and have implemented method equals
and hashCode
(for example you show strings or object with unique ID from database). First of all you iterate over all expanded nodes and save objects from the nodes in a set. Then you perform update of the model. After update you iterate over all nodes and if they are in the set you expand the node in the tree.
If nodes are not unique - you need to save in the set the complete tree path (for example as list) and check it after update to expand the nodes.
If objects has neither equals
nor hashCode
(both these methods must be implemented) - this variant cannot be used.
如果节点包含在树中唯一的对象并且已经实现了方法equals
和hashCode
(例如,您从数据库中显示具有唯一 ID 的字符串或对象),这很容易。首先,您遍历所有展开的节点并保存集合中节点中的对象。然后您执行模型的更新。更新后迭代所有节点,如果它们在集合中,则展开树中的节点。
如果节点不是唯一的 - 您需要在集合中保存完整的树路径(例如作为列表)并在更新后检查以扩展节点。
如果对象既没有equals
也没有hashCode
(必须实现这两个方法) - 不能使用此变体。
回答by chromanoid
Just for the record (I voted for Lee Meador), DefaultTreeModel#nodeChanged(javax.swing.tree.TreeNode)is the way to go:
只是为了记录(我投票给 Lee Meador),DefaultTreeModel#nodeChanged(javax.swing.tree.TreeNode)是要走的路:
public class TestFrame extends JFrame {
public TestFrame() {
//create gui with simple jtree (and DefaultTreeModel)
JButton changeBtn = new JButton();
final JTree jTree = new JTree();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
changeBtn.setText("update selected node");
getContentPane().add(changeBtn, java.awt.BorderLayout.PAGE_END);
DefaultMutableTreeNode treeNode1 = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode treeNode2 = new DefaultMutableTreeNode("blue");
treeNode1.add(treeNode2);
treeNode2 = new DefaultMutableTreeNode("violet");
DefaultMutableTreeNode treeNode3 = new DefaultMutableTreeNode("red");
treeNode2.add(treeNode3);
treeNode3 = new DefaultMutableTreeNode("yellow");
treeNode2.add(treeNode3);
treeNode1.add(treeNode2);
jTree.setModel(new DefaultTreeModel(treeNode1));
getContentPane().add(jTree, BorderLayout.CENTER);
pack();
//add listener to button, to change selected node on button click
changeBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
DefaultMutableTreeNode dmt = (DefaultMutableTreeNode)jTree.getSelectionPath().getLastPathComponent();
//update content/representation of selected node
dmt.setUserObject("My update: " + new Date());
//nodeChanged
((DefaultTreeModel) jTree.getModel()).nodeChanged(dmt);
}
});
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
}