Swing问题/ JTree /自定义树模型

我有一个问题和希望,有人知道出了什么问题,为什么并能够给我解释我现在错过的东西,让那件事情按照建议工作。

我有一个基于自定义TreeModel的JTree(“WRTreeModel”,见下文)。 该模型应用于的数据结构是包含一些字段的根对象的构建,以及由下面所示的“ArrayListModel”支持的列表。 当我使用WRTreeModel构建它时,树看起来很好。 我能够展开和折叠表示对象中包含的列表和字段的节点。 我可以展开和折叠这些列表并查看其内容等等。

现在我想删除其中一个列表的子节点 – 正如我所知 – 通过从调用ArrayListModel的remove方法的模型中删除它来实现它。 为了使WRTreeModel知道删除,首先要调用它的fireIntervalRemoved方法被调用,到目前为止一直这么好。

在WRTreeModels内部类ArrayModelListener中,intervalRemoved方法准备fireTreeNodesRemoved的调用,然后构建一个TreeEvent,该TreeEvent被转发到所有已注册的TreeModelListeners(因此当它连接到模型时,它自动注册自己的JTree)。

现在我希望树能够反映变化并更新它的内部和视觉表示以显示新状态。 不幸的是,这似乎并没有这样做。 有事情发生。 但是,当我点击节点时,我刚刚更改了一些EventHandler-Exceptions被抛出。 显然有些事情真的很混乱。

我知道在飞行中回答这样的问题并不容易,但我真的很感激快速回答。 如果有人知道网站解释使用自定义树模型(不是在DefaultMutableTreeNode或任何给定的基于实现的类)以及JTree的事件处理和更新如何工作,那也会有所帮助。

最诚挚的问候,

托马斯艺术


public class ArrayListModel extends ArrayList implements ListModel { ... public E remove(int index) { fireIntervalRemoved(index, index); E removedElement = super.remove(index); return removedElement; } ... } 

 public class WRTreeModel extends LogAndMark implements TreeModel { class ArrayModelListener implements ListDataListener { ... @Override public void intervalRemoved(ListDataEvent e) { int[] indices = new int[e.getIndex1() - e.getIndex0() + 1]; for (int i = e.getIndex0(); i < e.getIndex1(); i++) indices[i - e.getIndex0()] = i; fireTreeNodesRemoved(e.getSource(), getPathToRoot(e.getSource()), indices, ((ArrayListModel)e.getSource()).subList(e.getIndex0(), e.getIndex1()+1).toArray()); } ... } public Object[] getPathToRoot(Object child) { ArrayList ret = new ArrayList(); if (child == null) return ret.toArray(); ret.add(root); if (child == root) return ret.toArray(); int childType = 0; if (child instanceof List && ((List) child).get(0) instanceof Einleitungsstelle) { childType = 1; } if (child instanceof Einleitungsstelle) { childType = 2; } if (child instanceof List && ((List) child).get(0) instanceof Messstelle) { childType = 3; } if (child instanceof Messstelle) { childType = 4; } if (child instanceof List && ((List) child).get(0) instanceof Ueberwachungswert) { childType = 5; } if (child instanceof Ueberwachungswert) { childType = 6; } if (child instanceof List && ((List) child).get(0) instanceof Selbstueberwachungswert) { childType = 7; } if (child instanceof Selbstueberwachungswert) { childType = 8; } switch (childType) { // List of ESTs case 1: { ret.add(child); break; } // EST case 2: { List listOfEST = ((Wasserrecht) (root)).getListOfEST(); ret.add(listOfEST); ret.add(child); break; } // List of MSTs case 3: { List listOfEST = ((Wasserrecht) (root)).getListOfEST(); ret.add(listOfEST); // Find the EST containing the List of MSTs the child referes to for (Einleitungsstelle einleitungsstelle : listOfEST) { if (child == einleitungsstelle.getListOfMST()) { ret.add(einleitungsstelle); break; } } ret.add(child); break; } // MST case 4: { List listOfEST = ((Wasserrecht) (root)).getListOfEST(); ret.add(listOfEST); // Find the EST containing the List of MSTs the child referes to for (Einleitungsstelle einleitungsstelle : listOfEST) { if (child == einleitungsstelle.getListOfMST()) { ret.add(einleitungsstelle.getListOfMST()); break; } } ret.add(child); break; } // List of UEWs case 5: { List listOfEST = ((Wasserrecht) (root)).getListOfEST(); ret.add(listOfEST); // Find the EST containing the List of MSTs the child referes to for (Einleitungsstelle einleitungsstelle : listOfEST) { ArrayListModel listOfMST = einleitungsstelle.getListOfMST(); if (child == listOfMST) { ret.add(listOfMST); for (Messstelle messstelle : listOfMST) { if (child == messstelle.getListOfUEW()) { ret.add(messstelle.getListOfUEW()); break; } } break; } } break; } // UEW case 6: { List listOfEST = ((Wasserrecht) (root)).getListOfEST(); ret.add(listOfEST); // Find the EST containing the List of MSTs the child referes to for (Einleitungsstelle einleitungsstelle : listOfEST) { ArrayListModel listOfMST = einleitungsstelle.getListOfMST(); if (child == listOfMST) { ret.add(listOfMST); for (Messstelle messstelle : listOfMST) { if (child == messstelle.getListOfUEW()) { ret.add(messstelle.getListOfUEW()); break; } } break; } } ret.add(child); break; } // List of SUEWs case 7: { List listOfEST = ((Wasserrecht) (root)).getListOfEST(); ret.add(listOfEST); // Find the EST containing the List of MSTs the child referes to for (Einleitungsstelle einleitungsstelle : listOfEST) { ArrayListModel listOfMST = einleitungsstelle.getListOfMST(); if (child == listOfMST) { ret.add(listOfMST); for (Messstelle messstelle : listOfMST) { if (child == messstelle.getListOfSUEW()) { ret.add(messstelle.getListOfSUEW()); break; } } break; } } break; } // SUEW case 8: { List listOfEST = ((Wasserrecht) (root)).getListOfEST(); ret.add(listOfEST); // Find the EST containing the List of MSTs the child referes to for (Einleitungsstelle einleitungsstelle : listOfEST) { ArrayListModel listOfMST = einleitungsstelle.getListOfMST(); if (child == listOfMST) { ret.add(listOfMST); for (Messstelle messstelle : listOfMST) { if (child == messstelle.getListOfSUEW()) { ret.add(messstelle.getListOfSUEW()); break; } } break; } } ret.add(child); break; } default: ret = null; } return ret.toArray(); } } ... protected void fireTreeNodesRemoved(Object changed, Object path[], int childIndecies[], Object children[]) { TreeModelEvent event = new TreeModelEvent(this, path, childIndecies, children); synchronized (listeners) { for (Enumeration e = listeners.elements(); e.hasMoreElements();) { TreeModelListener tml = (TreeModelListener) e.nextElement(); tml.treeNodesRemoved(event); } } } ... } 

您需要在Event Dispatch Thread上执行节点删除和后续TreeModelListener.treeNodesRemoved事件触发。

为此,请使用:

 SwingUtilities.invokeLater( new Runnable() { public void run() { //Delete and event firing logic goes here. ... } } ); 

这样做可以防止Swing使用EDT在删除过程中更新树,并且事件触发告诉JTree控件(已添加侦听器)模型已更改。

因为我们赶时间,所以我还没有查看你的代码。 您的描述听起来好像在做正确的事情,并想到了所需要的东西。

我猜你可能没有考虑过的事情:这个树模型是否发生在Event Dispatch Thread(别名Swing worker thread)中? 如果更改来自另一个线程,则可能无法正确处理。

当然,只是在黑暗中刺伤。

看起来你在intervalRemoved中有一个off-by-one bug。

您没有初始化indices数组中的最后一个值。 它将自动初始化为0。

 @Override public void intervalRemoved(ListDataEvent e) { int[] indices = new int[e.getIndex1() - e.getIndex0() + 1]; for (int i = e.getIndex0(); i < e.getIndex1(); i++) indices[i - e.getIndex0()] = i; fireTreeNodesRemoved(e.getSource(), getPathToRoot(e.getSource()), indices, ((ArrayListModel)e.getSource()).subList(e.getIndex0(), e.getIndex1()+1).toArray()); } 

请改为“i <= e.getIndex1()”:

 for (int i = e.getIndex0(); i <= e.getIndex1(); i++) { indices[i - e.getIndex0()] = i; } 

方法名称为fireIntervalRemoved ,因此请删除尝试调用它:

 public E remove(int index) { E removedElement = super.remove(index); fireIntervalRemoved(index, index); return removedElement; } 

这是我做的方式,并且总是有效(可能还加了一些检查)。
(对不起,如果我错过了什么,没有时间分析/测试你的代码……)