我有一系列线程定期检索RSS提要,并希望使用PropertyChangeSupport刷新自定义JTree。但是它使用实现TreeModel的自定义类,我不知道如何触发自动更改。这可能还是我应该使用另一个班级?
答案 0 :(得分:3)
您必须使用模型的一组侦听器,当您的刷新线程注释某些更改时,您必须向它们触发事件。我不认为PropertyChangeSupport
会对您有所帮助,因为Tree模型的数据不是Java bean属性的形式,并且您不想触发PropertyChangeEvents。
在我最后做的TreeModel实现中,我制作了这些方法(德语评论:-p)
/**
* Benachrichtigt die Listener, dass die Struktur unterhalb
* eines bestimmten Knotens komplett geändert wurde.
*/
private void fireStructureChanged(TreePath path) {
TreeModelEvent event = new TreeModelEvent(this, path);
for(TreeModelListener lis : listeners) {
lis.treeStructureChanged(event);
}
}
/**
* Benachrichtigt die Listener, dass unterhalb eines Knotens
* einige Knoten entfernt wurden.
*/
private void fireNodesRemoved(TreePath parentPath,
int[] indices, Object[] nodes) {
TreeModelEvent event =
new TreeModelEvent(this, parentPath, indices, nodes);
for(TreeModelListener lis : listeners) {
lis.treeNodesRemoved(event);
}
}
/**
* Benachrichtigt die Listener, dass ein bestimmter Knoten
* entfernt wurde.
*/
private void fireNodeRemoved(TreePath path, int index, Object node) {
fireNodesRemoved(path, new int[]{index}, new Object[]{node});
}
/**
* Benachrichtigt die Listener, dass sich das Aussehen einiger
* Unterknoten eines Knotens geändert hat.
*/
private void fireNodesChanged(TreePath parentPath,
int[] indices, Object[] nodes) {
TreeModelEvent event =
new TreeModelEvent(this, parentPath, indices, nodes);
for(TreeModelListener lis : listeners) {
lis.treeNodesChanged(event);
}
}
/**
* Benachrichtigt die Listener, dass sich das Aussehen eines Knotens
* geändert hat.
*
* @param parentPath der Pfad des Elternknotens des relevanten Knotens.
* @param index der Index des Knotens unterhalb des Elternknotens.
* Falls < 0, werden die Listener nicht benachrichtigt.
* @param node der Subknoten.
*/
private void fireNodeChanged(TreePath parentPath,
int index, Object node) {
if(index >= 0) {
fireNodesChanged(parentPath, new int[]{index}, new Object[]{node});
}
}
/**
* Benachrichtigt die Listener, dass unterhalb eines Knotens einige
* Knoten eingefügt wurden.
*/
private void fireNodesInserted(TreePath parentPath,
int[] indices, Object[] subNodes) {
TreeModelEvent event =
new TreeModelEvent(this, parentPath, indices, subNodes);
for(TreeModelListener lis : listeners) {
lis.treeNodesInserted(event);
}
}
/**
* Benachrichtigt die Listener, dass ein Knoten eingefügt wurde.
*/
private void fireNodeInserted(TreePath parentPath,
int index, Object node) {
fireNodesInserted(parentPath, new int[]{index}, new Object[]{node});
}
然后,从模型的其他部分开始,只要有变化,就会调用正确的方法。
如果你想简化它,你可以简单地总是用根节点触发treeStructureChanged
事件,这将导致整个树重新加载。对于更精细的事件,你需要查看事实上发生了什么变化,并解雇它。
答案 1 :(得分:2)
不完全确定,你用“通过使用PropertyChangeListener刷新树”是什么意思,但是同意Paul:在通知treeModel侦听器(包括JTree)中,PropertyChangeListener没有帮助。
TreeModel的任何实现都是通过适当的TreeModelEvents通知其侦听器的内在责任。如果它侦听包含节点的更改(可能触发f.i. PropertyChangeEvents),那么它必须将它们转换为TreeModelEvents。
伪代码段:
public class MyTreeModel implements TreeModel {
PropertyChangeListener nodeListener;
// custom method to insert a node
public void addNodeTo(MyBean child, MyBean parent) {
// ... internal logic to add the new node
fireChildAdded(getPathToRoot(parent), child)
// add a PropertyChangeListener to new node so the model
// can comply to its notification contract
child.addPropertyChangeListener(getPropertyChangeListener();
}
protected void nodePropertyChanged(MyBean bean) {
firePathChanged(getPathToRoot(bean));
}
protected TreePath getPathToRoot(MyBean bean) {
// construct and return a treePath to the root
}
protected PropertyChangeListener getPropertyChangeListener() {
if (nodeListener == null) {
nodeListener = new PropertyChangeChangeListener() {
public void propertyChanged(...) {
nodeChanged((MyBean) e.getSource();
}
);
}
}
构建实际事件有点令人困惑(并且文档记录很少),这就是SwingX has a helper class TreeModelSupport简化该任务的原因。