# JTree Knoten schliessen



## Pingu (30. Mrz 2009)

Hallo zusammen

Habe bisher nicht im Forum gefunden was mich weiterbringt.

Also folgendes:

Ich habe einen JTree. Wenn der Benutzer nun über eine Suche ein Element sucht, werden alle zutreffenden Elemente im Baum aufgeklappt und selektiert.

Setzt er eine neue Suche ab so müssen vorher alle offenen Knoten wieder geschlossen werden.

Habe das mal was mit JTree.collapsePath(...) ausprobiert wobei ich ihm alle selektierten Pfade mitgegeben habe.

Wenn der Benutzer aber inzwischen die Selektion wechselt, dann werden die offenen Knoten nicht geschlossen.

Hat von euch jemand eine Lösung oder Idee?

Gruss


----------



## Ebenius (30. Mrz 2009)

Ich habe das Problem noch nicht richtig verstanden.


Pingu hat gesagt.:


> Wenn der Benutzer aber inzwischen die Selektion wechselt, dann werden die offenen Knoten nicht geschlossen.


Wann ist "inzwischen"? Was ist genau das Verhalten das Du möchtest? Hilft vielleicht ein bisschen Quelltext weiter?

Ebenius


----------



## Pingu (30. Mrz 2009)

Ebenius hat gesagt.:


> Ich habe das Problem noch nicht richtig verstanden.
> 
> Wann ist "inzwischen"? Was ist genau das Verhalten das Du möchtest? Hilft vielleicht ein bisschen Quelltext weiter?
> 
> Ebenius




Also der Benutzer sucht Beispielsweise Apfel


```
+Frucht
  |> Apfel
     |> Frischer Apfel
  |> Banane
+Gemüse
```

So wird ihm hier "Apfel" und "Frischer Apfel" selektiert.

Nun will er eine zweite Suche absetzten so werden vorher alle Knoten Elemente geschlossen. Also man sieht nur noch.


```
+Frucht
+Gemüse
```

Wenn der Benutzer aber zwischend der ersten und zweiten suche noch "Gemüse" öffnet und Tomate auswählt.



```
+Frucht
  |> Apfel
     |> Frischer Apfel
  |> Banane
+Gemüse
  |> Tomate
  |> Kürbis
```

So wird "Gemüse" geschlossen aber "Apfel" und "Frucht" nicht mehr.

Was ich nun will, dass bei einer neuen Suche der ganze Baum geschlossen wird und zwar auch alle offenen Knoten.

Klar?


```
private void collapseTree(){
		TreePath[] selectedPaths = getFrame().getDocTypeTree().getSelectionPaths();
		for(TreePath path : selectedPaths){
			getFrame().getDocTypeTree().collapsePath(path.getParentPath());
		}
	}
```


----------



## Ebenius (30. Mrz 2009)

Du willst also einfach alle Knoten schließen die offen sind? Egal was sonst noch passiert ist? Das hättest Du oben wirklich weniger ausschweifend erklären können. 

Das geht in etwa so: [HIGHLIGHT="Java"]/** Collapses the whole tree */
public void collapseAll(JTree tree) {
  final TreeModel tm = tree.getModel();
  final Object root = tm.getRoot();

  /* nothing to expand, if no root */
  if (root != null) {
    collapseAllPaths(tree, new TreePath(root));
  }
}

/**
 * Collapses all paths in the given node and all nodes below that.
 * 
 * @param path the tree path to the node to collapse
 * @see JTree#expandPath(TreePath)
 */
public void collapseAllPaths(JTree tree, TreePath path) {
  final TreeModel treeModel = tree.getModel();
  tree.cancelEditing();
  tree.collapsePath(path);
  final Object node = path.getLastPathComponent();
  final int n = treeModel.getChildCount(node);
  for (int index = 0; index < n; index++) {
    final Object child = treeModel.getChild(node, index);
    if (!treeModel.isLeaf(child)) {
      collapseAllPaths(tree, path.pathByAddingChild(child));
    }
  }
}[/HIGHLIGHT]
Ebenius


----------



## Pingu (30. Mrz 2009)

Klappt nicht. Die Knoten werden teils aufgeklappt...


----------



## Ebenius (30. Mrz 2009)

Dann wirst Du wohl mal Quelltext hergeben müssen. 

Ebenius


----------



## Pingu (30. Mrz 2009)

```
public void search(String doctype) {
		if(doctype.isEmpty())
			return;
		
		collapseTree(getFrame().getDocTypeTree());
		getFrame().getDocTypeTree().clearSelection();
		if(doctype.startsWith("*")){
			if(doctype.endsWith("*")){
				doctype = doctype.replace("*", "");
				for (DocType myDocType: myDoctypeList) {
					if(myDocType.getBezeichnungDt().toLowerCase().contains((CharSequence)doctype.toLowerCase())){
						getFrame().getDocTypeTree().addSelectionPath(myDocType.getTreePath());
					}
				}
			}else{
				doctype.replace("*", "");
				for (DocType myDocType: myDoctypeList) {
					if(myDocType.getBezeichnungDt().toLowerCase().endsWith(doctype.toLowerCase())){
						getFrame().getDocTypeTree().addSelectionPath(myDocType.getTreePath());
					}
				}
			}
		}
		else if(doctype.endsWith("*")){
			doctype = doctype.replace("*", "");
			for (DocType myDocType: myDoctypeList) {
				if(myDocType.getBezeichnungDt().toLowerCase().startsWith(doctype.toLowerCase())){
					getFrame().getDocTypeTree().addSelectionPath(myDocType.getTreePath());
				}
			}	
		}
		else{
			for (DocType myDocType: myDoctypeList) {
				if(myDocType.getBezeichnungDt().toLowerCase().equals(doctype.toLowerCase())){
					getFrame().getDocTypeTree().addSelectionPath(myDocType.getTreePath());
				}
			}	
		}
	}
	
	private void collapseTree(JTree tree){
		final TreeModel tm = tree.getModel();
		final Object root = tm.getRoot();
		
		if (root != null) {
			collapseAllPaths(tree, new TreePath(root));
		}
	}
	
	public void collapseAllPaths(JTree tree, TreePath path) {
		final TreeModel treeModel = tree.getModel();
		
		tree.cancelEditing();
		tree.collapsePath(path);
		
		final Object node = path.getLastPathComponent();
		final int n = treeModel.getChildCount(node);
		
		for (int index = 0; index < n; index++) {
			final Object child = treeModel.getChild(node, index);
			if (!treeModel.isLeaf(child)) {
				collapseAllPaths(tree, path.pathByAddingChild(child));
			}
		}
	}
```


----------



## Ebenius (30. Mrz 2009)

Geht das auch nicht, wenn Du erst die Selektion leer machst und danach die Knoten schließt?

Ebenius


----------



## Pingu (30. Mrz 2009)

Funktioniert nun teils.

Seltsam ist nur, dass ein Knoten immer geöffnet wird obwohl das gesuchte Element nicht vorhanden ist.

Und zusätzlich wird, wenn bei der Suche kein Treffer erfolgt das Model nicht mehr aufbereitet ich habe also einen leeren JTree.


----------



## Pingu (30. Mrz 2009)

Pingu hat gesagt.:


> Funktioniert nun teils.
> 
> Seltsam ist nur, dass ein Knoten immer geöffnet wird obwohl das gesuchte Element nicht vorhanden ist.
> 
> Und zusätzlich wird, wenn bei der Suche kein Treffer erfolgt das Model nicht mehr aufbereitet ich habe also einen leeren JTree.



Das zweite Problem mit dem Model hab ich gelöst. Wieso er aber ein Knoten immer öffnet bleibt mir ein Rätsel.


----------



## Ebenius (30. Mrz 2009)

Läuft die Suche in einem ausgelagerten Thread (sprich, außerhalb des Event Dispatch Thread)? Dann müssen natürlich alle Zugriffe auf Baum und Modell synchronisiert werden; am besten per SwingUtilities.invokeLater(Runnable).

Ebenius


----------



## Pingu (30. Mrz 2009)

Nein läuft alles im selben Thread.


----------



## Ebenius (30. Mrz 2009)

Hmm. So kann ich Dir erstmal nicht weiter helfen. Lass Dir doch mal alle geschlossenen Pfade ausgeben und schau mal, ob der der am Ende offen ist auch dabei ist. Vielleicht öffnest Du den Pfad woanders nochmal??? Keine Ahnung.

Ebenius


----------



## Pingu (30. Mrz 2009)

Ok werde das mal versuchen.

Danke für die Hilfe.


----------



## Pingu (30. Mrz 2009)

Ich habe nun mit getExpandedDescendants herausgefunden, dass der Knonten nach dem Schliessen aller Knoten geöffnet ist. Was ja klar war.

Habe dann versucht mit Breakpoints auf die Methoden expandPath und expandRow zu schauen wann der Knoten geöffnet wird. Sie wird mit diesem Knoten aber nie aufgerufen :S


----------



## Ebenius (30. Mrz 2009)

Du könntest noch im BasicTreeUI nach "treeState.setExpandedState(path, true);" suchen und die Stellen debuggen.

Ebenius


----------



## Pingu (31. Mrz 2009)

So Lösung gefunden:

[HIGHLIGHT="Java"]
       public void collapseAll(JTree tree) {
		int row = tree.getRowCount() - 1;
		while (row >= 0) {
			tree.collapseRow(row);
			row--;
		}
	}
[/HIGHLIGHT]


----------

