更新/刷新 TreeModel

发布于 2024-10-25 05:30:21 字数 122 浏览 3 评论 0原文

我有一系列定期检索 RSS 提要的线程,并且想要使用 PropertyChangeSupport 刷新自定义 JTree。但是它使用实现 TreeModel 的自定义类,我不确定如何触发自动更改。这是可能的还是我应该使用另一个类?

I have a series of threads retrieving RSS feeds at regular intervals and want to refresh a custom JTree using PropertyChangeSupport. However it uses a custom class implementing TreeModel and I'm not sure how to trigger an automatic change. Is this possible or should I use another class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一身骄傲 2024-11-01 05:30:21

您必须使用模型的侦听器集合,并且当您的刷新线程注意到某些更改时,您必须向它们触发事件。我认为 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 事件,这将导致整个树重新加载。对于更精细的事件,您需要查看实际上发生了什么变化,然后触发它。

You'll have to use a collection of listeners of your model, and when your refreshing thread remarks some changes, you'll have to fire events to them. I don't think PropertyChangeSupport will help you here much, as the Tree model's data is not in the form of Java beans properties, and you don't want to fire PropertyChangeEvents.

In a TreeModel implementation I did lastly, I made these methods (with german comments :-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});
}

Then from the other parts of the model the right methods were invoked whenever something changed.

If you want to make it simple, you could simple always fire a treeStructureChanged event with the root node, which would cause the whole tree to reload. For finer events, you'll need to look what in fact changed, and fire this.

音栖息无 2024-11-01 05:30:21

不完全确定“使用 PropertyChangeListener 刷新树”是什么意思,但同意 Paul 的观点:PropertyChangeListener 对于通知 treeModel 侦听器(包括 JTree)没有帮助。

通过适当的 TreeModelEvents 通知其侦听器是 TreeModel 的任何实现的固有责任。如果它侦听所包含节点的更改(可能会触发 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 有一个辅助类 TreeModelSupport 来简化该任务。

Not entirely sure, what you mean by "refresh a tree by using a PropertyChangeListener", but agree with Paul: a PropertyChangeListener is not helpful in notifying the treeModel listeners (which include the JTree).

It is an intrinsic responsibility of any implementation of a TreeModel to notify its listeners by means of appropriate TreeModelEvents. If it listens to changes of contained nodes (which might fire f.i. PropertyChangeEvents) then it must translate those to TreeModelEvents.

A pseudo-code snippet:

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();
                 }

             );
     }

}

Constructing the actual events be a bit confusing (and is poorly documented), that's why SwingX has a helper class TreeModelSupport to simplify that task.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文