2012-05-03 3 views
0

을 편집 한 후 JTree에있는 노드를 축소하지 방법 :노드가 I이 기능을 구현하는 방법을 알고 싶어

내가 노드의 이름을 편집 할 수있는 편집 가능한 JTree가 있습니다. 편집 할 때 분기 노드 (일부 리프 노드가 있음)가 있고이 분기 노드가 편집 중에 확장되면이 노드가 축소됩니다.

열려있는 경우 해당 분기 노드를 열어두고 편집이 완료되면 접힌 경우 축소됩니다.

방법이 트릭을 할 ...

나는 TreeWillExpandListener보고 시도했지만 내가이 메소드를 호출하기 전에 실제 노드 편집 모드에있는 경우 인식 할 필요가 있기 때문에 내 문제가 해결되지 않는 것 같다? 그것은 너무 분명한 일이지만 필요한 모든 답변을 찾을 수 없습니다 :/

좋아,이 코드는, 내가 그것을 설명하려고합니다. 우선, TreeModel을 구현하는 ContactTreeModel 클래스가 있습니다. 생성자는 주 앱 프레임에서 주소록과 그룹 관리자를로드하기 만하면 새 루트를 만들고 두 번째 방법에서는 데이터베이스에서 데이터를로드합니다.

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을 확장하지 않았으므로 사용하려고하기 때문에 시도하지 않아도됩니다. ... 실제로이 Metod가 제공되는 DefaultTreeModel의 확장으로 TreeModel 인터페이스 구현에서 실제로 다시 작성하고 있습니다. – stewenson

+0

@ Stefan.M 내 재 방문 답변이 도움이되는지 확인하십시오. – tenorsax

+0

잘못된'TreeModelEvent' 생성자를 사용합니다. [docs에 명시된대로] (http://goo.gl/QL3br),이 생성자는'treeStructureChanged()'에만 ** ** 사용할 수 있습니다. 자세한 내용은 [이 답변] (http://goo.gl/dZDT5)을 참조하십시오. –

관련 문제