2009-12-10 9 views
5

私は問題を抱えています。誰かが間違っていることを知っていますし、なぜ、私がそのことを今のようにするために欠けているのかについての説明を私に与えることができます。提案する。スイング質問/ JTree /カスタムツリーモデル

私は、カスタムTreeModel( "WRTreeModel"、以下を参照)を基に作成したJTreeを持っています。 このモデルを使用するデータ構造は、いくつかのフィールドを含むルートオブジェクトのビルドであり、さらに、以下に示す "ArrayListModel"によってサポートされるリストです。 WRTreeModelを使用してツリーを構築すると、ツリーが正常に表示されます。私は、オブジェクトに含まれるリストとフィールドを表すノードを展開して折り畳むことができます。 これらのリストを展開したり折り畳んだりすることができます。

リストの1つの子を削除したいと思います。既に知っているように、ArrayListModelのremoveメソッドを呼び出すモデルからモデルを削除することで行います。 WRTreeModelが削除を認識するようにするには、最初にfireIntervalRemovedメソッドを呼び出す方法があります。 intervalRemoved方法は、すべての登録 TreeModelListeners(したがって、それがモデルに接続したときにそれ自体がautomaticallレジスタJTreeの)に転送されるTreeEventを構築fireTreeNodesRemovedの呼び出しを準備ArrayModelListener WRTreeModels内部クラスで

ここで、ツリーが変更を反映し、新しい状態を示すための内部的および視覚的な表示を更新することが期待されます。 残念ながら、これはそのようには動作していないようです。何かが起こる。しかし、ノードをクリックすると、EventHandlerの例外がいくつか変更されました。例外がスローされます。明らかに何かが本当に混乱しました。

このような質問にすぐに答えるのは簡単ではないことはわかっていますが、私は本当に速い答えに感謝します。 カスタムツリーモデル(DefaultMutableTreeNodeまたは任意の実装ベースのクラスではない)の使用を説明するWebサイトと、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); 
     } 
     } 
    } 

... 

} 
+0

さらに助けになるかどうかわかりませんが、削除したノードの親ノードを折りたたんで展開しようとすると、次の例外が発生します。 スレッド「AWT-EventQueue-0」の例外java.lang。 javax.swing.plaf.basic.BasicTreeUI.ensureRowsAreVisible(BasicTreeUI.java:1881)するjavax.swingにおける javax.swing.plaf.basic.BasicTreeUI.toggleExpandStateで\t(BasicTreeUI.java:2208) \tでNullPointerExceptionが \t。 plaf.basic.BasicTreeUI.handleExpandControlClick(BasicTreeUI.java:2191) \t javax.swing.plaf.basic.BasicTreeUI.checkForClickInExpandControl(BasicTreeUI.java:2149) \t at ... and so on –

+0

すべての問題は定義上緊急です:-)質問に「時間の圧力」は言及しません。あなたの質問は、あなたが長いこと忘れてしまったときに他の人を助け、助けてくれることを意味します。より標準的にする。 – raoulsson

答えて

2

あなたは削除して、イベントディスパッチスレッド上で発射以降のTreeModelListener.treeNodesRemovedイベントノードを実行する必要があります。これは、モデルという(リスナーを追加しました)あなたの削除やイベントの発火が伝えJTreeの制御の途中でツリーを更新するために、EDTを使用してスイングを防ぎ行う

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

は、この使用を行うには変更されました。

+0

それに加えて、次のexpandToPath(path)を持つTree.updateUI()削除された要素の親は、私が望む仕事を正確に行います。 ありがとう、そのヒント! BTW:SwingUtilities.invokeLaterを使用しているように見えるので、誰も自分のイベントやUIの内容を忘れてしまうと思います。 –

+0

+1私の考えを溶かすため。 –

+0

@Carl:ありがとう:-) –

0

私たちは、私はまだあなたのコードを見ていない急いでいるので。あたかもすべてを正しくやっているかのようにあなたの説明が聞こえ、必要なことを考えています。

私はあなたが考えていないかもしれないと思います:このツリーモデルの変更は、イベントディスパッチスレッド(別名スイングワーカースレッド)で起こっていますか?変更が別のスレッドから発生した場合、適切に処理されない可能性があります。

もちろん、暗闇の中でちょうど刺す。

+0

私はそれが正しいスレッドで起こっていると思います。 fireTreeNodesRemovedメソッドでブレークポイントを持つようにデバッグすると、AWT-EventQueueスレッドで停止します。それは正しいと思われる。 –

+0

あなたはそうです。上記の答えを参照してください、実際にはそれは魅力のように動作します:-) –

+0

優秀!私はあまりにも急いでいた(申し訳ありませんが、会議に出席しなければならなかった)、修正を推奨する機会はありませんでした。 –

0

intervalRemovedにoff-by-oneバグがあるようです。

インデックス配列の最後の値を初期化していません。 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()); 
} 

代わりに "私< = e.getIndex1()" お試しください:メソッド名がfireIntervalRemovedですので、取り外し後それを呼び出してみてください

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

あなたはそれに絶対に合っています。メソッド記述にも同じことが記述されています。削除しようとしているリスト要素が最初であるため、インデックス0は問題ないので、私の問題には何の影響も与えませんでしたが、修正しました。 –

0

を:

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

これは私がやったやり方で、いつも働いています(おそらくいくつかのチェックを追加したかもしれません)。
(私が何かを逃した場合は申し訳ありませんが、あなたのコードをテスト/ analiseまでにお時間を頂くdid'nt ...)

+0

TreeEventを構築するために削除された要素を知る必要はありませんか? 要素を削除した後にfireIntervalRemoved(index、index)を呼び出すと、それ以上取得できなくなります。 これは、リストからの実際の削除前にコールを移動した理由です。 –

+0

わかりません。すべてのコードをチェックしておらず、 'fireIntervalRemoved'が見つかりません。私が知っているように、TreeModelEventは要素を必要としません...あなたが要素を削除する前に、イベントを発生させ、GUIが更新された(十分速い)と思うと、ツリーは削除を反映しません( )。おそらく、あなたは要素を削除する前にイベントを構築し、削除後にイベントを発生させるかもしれません。((* Gruss aus Stuttgart *) –