5

我遇到了问题和希望,有人知道出了什么问题以及原因,并且能够向我解释我现在错过了什么,以使该事情按建议工作。

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

现在我想删除其中一个列表的一个子项,并且 - 正如我已经知道的那样 - 通过从调用 ArrayListModel 的 remove 方法的模型中删除它来完成。为了让 WRTreeModel 知道那个 remove,第一件事就是调用它的 fireIntervalRemoved 方法被调用,到目前为止一切顺利。

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

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

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

最诚挚的问候,

托马斯艺术


public class ArrayListModel<E> extends ArrayList<E> 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<Object> ret = new ArrayList<Object>();
    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<Einleitungsstelle> listOfEST = ((Wasserrecht) (root)).getListOfEST();
      ret.add(listOfEST);
      ret.add(child);
      break;
    }
    // List of MSTs
    case 3: {
      List<Einleitungsstelle> 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<Einleitungsstelle> 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<Einleitungsstelle> listOfEST = ((Wasserrecht) (root)).getListOfEST();
        ret.add(listOfEST);
        // Find the EST containing the List of MSTs the child referes to
       for (Einleitungsstelle einleitungsstelle : listOfEST) {
         ArrayListModel<Messstelle> 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<Einleitungsstelle> listOfEST = ((Wasserrecht) (root)).getListOfEST();
      ret.add(listOfEST);
      // Find the EST containing the List of MSTs the child referes to
      for (Einleitungsstelle einleitungsstelle : listOfEST) {
        ArrayListModel<Messstelle> 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<Einleitungsstelle> listOfEST = ((Wasserrecht) (root)).getListOfEST();
      ret.add(listOfEST);
      // Find the EST containing the List of MSTs the child referes to
      for (Einleitungsstelle einleitungsstelle : listOfEST) {
        ArrayListModel<Messstelle> 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<Einleitungsstelle> listOfEST = ((Wasserrecht) (root)).getListOfEST();
       ret.add(listOfEST);
       // Find the EST containing the List of MSTs the child referes to
       for (Einleitungsstelle einleitungsstelle : listOfEST) {
          ArrayListModel<Messstelle> 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);
      }
      }
    }

...

}
4

4 回答 4

2

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

为此,请使用:

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

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

于 2009-12-10T17:02:04.047 回答
0

因为我们很着急,所以我还没有查看您的代码。你的描述听起来好像你做的一切都是正确的,并且已经想到了需要什么。

我对您可能没有考虑过的事情的猜测:这种树模型更改是否发生在事件调度线程(别名 Swing 工作线程)中?如果更改来自另一个线程,则很可能无法正确处理它。

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

于 2009-12-10T13:54:19.417 回答
0

看起来您在 intervalRemoved 中有一个错误。

您没有初始化索引数组中的最后一个值。它将自动初始化为 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;
}
于 2009-12-10T14:31:00.500 回答
0

方法名称是fireIntervalRemoved,所以删除 后尝试调用它:

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

这是我所做的方式,并且一直有效(也许添加了一些检查)。
(对不起,如果我错过了什么,没有时间分析/测试你的代码......)

于 2009-12-10T14:53:27.633 回答