2012-05-03 17 views
0

を編集された後JTreeの中でノードを折りたたむない方法:ノードが、私はこの機能を実装する方法を知りたい

私は、ノードの名前を編集することができ、編集可能なJTreeのを持っています。私はいくつかの枝ノード(それにいくつかの葉ノードを持っています)を持っていて、編集中にこの枝ノードが展開されていると、編集後、このノードは崩壊します。

開いている場合はブランチノードを開いたままにしておき、折りたたまれている場合は編集後に折りたたんでいます。

どのようにこのトリックを行うために...

私はTreeWillExpandListenerを見てみましたが、私が、私はこれらのメソッドを呼び出す前に、実際のノードが編集モードであるかどうかを認識する必要があるので、それは私の問題を解決しないと思われますか?あまりにも明白ですが、私は答えを見つけることができません:/

これはコードなので、私はそれを説明しようとします。まず第一に、TreeModelを実装するContactTreeModelクラスがあります。コンストラクタはメインのアプリケーションフレームからアドレス帳とグループマネージャをロードするだけで、新しいルートを作成し、2番目の方法でデータベースからデータをロードします。

public ContactTreeModel() { 
    addressBookManager = ContactManagerFrame.getAddressBookManager(); 
    groupManager = ContactManagerFrame.getGroupManager(); 
    root = new DefaultMutableTreeNode(); 
    processTreeHierarchy(); 
} 

private void processTreeHierarchy() { 
    DefaultMutableTreeNode group, contact; 
    for (Group g : addressBookManager.getGroups()) { 
     group = new DefaultMutableTreeNode(g); 
     root.add(group); 
     for (Contact c : addressBookManager.getContactsFromGroup(g)) { 
      contact = new DefaultMutableTreeNode(c); 
      group.add(contact); 
     } 
    } 
} 

Iは、ユーザがnewValueにパスによって識別される項目の値を変更したときにメッセージとして送ら

場合TreeModelのメソッドvalueForPathChangedが解雇されていること。読み取りますnewValueが本当に新しい値を示す場合、モデルはtreeNodesChangedイベントをポストする必要があります。

だから私はこのような方法と書きました:

@Override 
public void valueForPathChanged(TreePath path, Object newValue) { 
    // backup of the original group 
    Group oldGroup = (Group) path.getLastPathComponent(); 
    try { 
     Group testGroup = (Group) path.getLastPathComponent(); 
     testGroup.setName((String) newValue); 
     // validation of the group to be updated 
     groupManager.validateGroup(testGroup, true); 
     oldGroup.setName((String) newValue); 
     // updating of the group in db 
     groupManager.updateGroup(oldGroup); 
    } catch (ServiceFailureException | ValidationException ex) { 
     // if database error occured or validation exception is raised, 
     // update label in gui 
     ContactManagerFrame.getStatusPanelLabel().setText(ex.getMessage()); 
    } finally { 
     fireTreeStructureChanged(); 
    } 
} 

お知らせfinallyブロック内のメソッド、そのメソッドは、常に解雇されます。それはのように見える

protected void fireTreeStructureChanged() { 
    Object[] o = {root}; 
    TreeModelEvent e = new TreeModelEvent(this, o); 
    for (TreeModelListener l : treeModelListeners) { 
     l.treeNodesChanged(e); 
    } 
} 

これは少しトリッキーで、なぜそれが動作しない(私は推測する)理由です。私はすべてのtreeModelListenerを繰り返し実行し、treeNodesChangedメソッドを起動します。

私もContactTreeModelおよび関連する方法でプライベート属性としてツリーモデルリスナーのために指定された配列している:最後のもの

private Vector<TreeModelListener> treeModelListeners = new Vector<>(); 

@Override 
public void addTreeModelListener(TreeModelListener l) { 
    treeModelListeners.addElement(l); 
} 

@Override 
public void removeTreeModelListener(TreeModelListener l) { 
    treeModelListeners.removeElement(l); 
} 

は、どのように私がモデルに追加モデルリスナーが見えますか?ここに来る:

public class ContactTreeModelListener implements TreeModelListener { 
    @Override 
    public void treeNodesChanged(TreeModelEvent e) { 
     System.out.println("nodes changed"); 
    } 

    @Override 
     public void treeNodesInserted(TreeModelEvent e) { 
     System.out.println("nodes inserted"); 
    } 

    @Override 
    public void treeNodesRemoved(TreeModelEvent e) { 
     System.out.println("nodes removed"); 
    } 

    @Override 
    public void treeStructureChanged(TreeModelEvent e) { 
     System.out.println("structure changed"); 
    } 
} 

これは基本的に何もしません。私は他の場所にリスナーを登録しましたが、今は関係ありません。

私はそれを実行すると、この状態では、ツリーは崩壊しておらず、その振る舞いは望まれます。しかし、元の文字列が約5文字で、それを4文字に変更した場合、ラベルには4文字だけでなく、5行目の空白も表示されますが、実際にはそのノード(ラベル)の名前が書き換えられます。そのラベルの編集が終わったら、元のラベルのサイズは変わりません。同様に、グループの名前を拡張すると、 というように4から5文字に名前を変更します。そのノードのラベルには、テキスト全体が表示するには大きすぎる を示すドットが含まれます。それは変です...どのように私はそのラベルのudpdate を作るのですか?

最後のこと...私はJTree +でカスタムアイコンを持っているので空のグループと非空のグループの間で認識を行います。ツリー内で何らかのアクションを実行するたびにdbの実際のアイコンをチェックする必要があります(私はノードを開いて閉じていても実行されていることを確認しました)。私は実際にキャッシングを行うDefaultTreeCellRendererを延長してこれは非常に非効率的である:

@Override 
public Component getTreeCellRendererComponent(
     JTree tree, 
     Object value, 
     boolean sel, 
     boolean expanded, 
     boolean leaf, 
     int row, 
     boolean hasFocus) { 

    if (iconCache == null) { 
     throw new NullPointerException("iconCache in " 
      + this.getClass().getName() + " is null"); 
    } 

    super.getTreeCellRendererComponent(
      tree, value, sel, 
      expanded, leaf, row, 
      hasFocus); 

    if (value instanceof Group) { 
     Group g = (Group) value; 
     Icon groupIcon = iconCache.get(g); 
     if (groupIcon == null) { 
      if (groupHasContacts(g)) { 
       groupIcon = groupNonEmpty; 
      } else { 
       groupIcon = groupEmptyIcon; 
      } 
      iconCache.put(g, groupIcon); 
     } 
     JLabel result = (JLabel) super.getTreeCellRendererComponent(tree, 
       g.getName(), sel, expanded, leaf, row, hasFocus); 

     result.setIcon(groupIcon); 
     return result; 
    } 
    else if (value instanceof Contact) { 
     Contact c = (Contact) value; 
     Icon icon = iconCache.get(c); 
     if (icon == null) { 
      icon = this.contactIcon; 
      iconCache.put(c, icon); 
     } 
     JLabel result = (JLabel) super.getTreeCellRendererComponent(
       tree, c.getName() + c.getSurname(), 
       sel, expanded, leaf, row, hasFocus); 
     result.setIcon(icon); 
     return result; 
    } 

    JLabel defaultNode = (JLabel) super.getTreeCellRendererComponent(
      tree, "?", sel, expanded, leaf, row, hasFocus); 

    defaultNode.setIcon(unknownNode); 
    return defaultNode; 
} 
+1

なぜ最初から崩壊していますか?問題を説明する[SSCCE](http://sscce.org/)を共有してください。 – tenorsax

+0

@Max説明のためにいくつかのコードを追加しました。役立つことを願っています... – stewenson

答えて

0

おそらくあなただけroot中でtreeNodesChangedイベントを発生するという事実に関連して、正しく再描画されていないラベルの更新に伴う問題パスを識別する配列。

valueForPathChangedから、次を呼び出すようにしてください:

public void fireTreeNodesChanged(TreePath path) { 
    TreeModelEvent e = new TreeModelEvent(this, path.getPath()); 
    for (TreeModelListener l : treeModelListeners) { 
     l.treeNodesChanged(e); 
    } 
} 

ところで、実際にtreeNodesChangedを発射fireTreeStructureChangedためのあなたの名前は非常に誤解を招きやすいです。

+0

TreeModelを実装し、DefaultTreeModelを拡張しないので、それを使用するためにはコード化する必要があります。 ...私は実際には、TreeModelインターフェースの実装からこのMetodが提供されるDefaultTreeModelの拡張に書き直しています。 – stewenson

+0

@ Stefan.M私の再訪された回答があなたに役立つかどうかを確認してください。 – tenorsax

+0

あなたは間違った 'TreeModelEvent'コンストラクタを使います。 [docsに記載されている](http://goo.gl/QL3br)と同様に、このコンストラクタは 'treeStructureChanged()'に** **のみ使用できます。詳細は、[この回答](http://goo.gl/dZDT5)を参照してください。 –

関連する問題