# Jede node in JTree mit eigenem Icon



## DStrohma (27. Jul 2010)

Hi,

ich hab hier folgendes Problem: Ich habe einen Vector mit "Report"-Objekten. ich lade jedes dieser Report-Objekte in jeweils eine Node und stelle das Ganze dann in einem JTree dar. Geht auch alles, nur leider schaff ich es nicht dass jede Node ihr eigenes Icon hat...

Bis jetzt habe ich das folgender Maßen:

```
for (ReportTemplate report : reports) {

            // Create node.
            DefaultMutableTreeNode node;
            node = new DefaultMutableTreeNode(report.getNodeName());
            node.setUserObject(report);

            // Set icon for the node.
            DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
            renderer.setLeafIcon(report.getIcon());
            tree.setCellRenderer(renderer);

            // Add node to tree.
            model.insertNodeInto(node, root, root.getChildCount());
            model.reload();

            cardPanel.add(report.getCardPanel(), report.getNodeName());
        }
```

Das Problem ist hier, dass jede Node genau das Icon hat, das als letztes gesetzt worden ist. Heißt, das LeafIcon wird für jede Node des Baumes gesetzt. Ich will es aber nur für die aktuelle Node setzen. Irgend eine Idee wie das geht?

Ich hab auch schon versucht einen eigenen Renderer zu erstellen und diesem Renderer das Report-Objekt zu übergeben, damit sich der Renderer das Icon aus dem Report-Objekt laden kann. Führt zu dem gleichen Ergebnis.


```
for (ReportTemplate report : reports) {

            // Create node.
            DefaultMutableTreeNode node;
            node = new DefaultMutableTreeNode(report.getNodeName());
            node.setUserObject(report);

            // Set icon for the node.
            ReportCellRenderer renderer = new ReportCellRenderer(report);
            tree.setCellRenderer(renderer);

            // Add node to tree.
            model.insertNodeInto(node, root, root.getChildCount());
            model.reload();

            cardPanel.add(report.getCardPanel(), report.getNodeName());
        }
```

Und der Renderer:

```
public class ReportCellRenderer extends DefaultTreeCellRenderer {
    ReportTemplate report;

    public ReportCellRenderer(ReportTemplate report) {
        this.report = report;
    }

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

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

        setIcon(report.getIcon());

        return this;
    }
}
```


----------



## sylo (27. Jul 2010)

Hi

vielleicht kann ich dir einen Hinweis geben, aber genau weis ich nicht wie es geht. Hab es nicht ausprobiert.

Ich habe mal gesehen, dass einer sich eine eigene Node Klasse geschrieben hat. Dies hat er gemacht um eine Objektvariable namens "valid" hinzuzufügen. Anhand dieser variablen konnte er dann feststellen ob sie gültig ist und diese dann im CellRenderer rot oder schwarz darstellen. Das müsste doch auch bei dir funktionieren, wenn du anstatt einen bool Wert, einen Icon Wert nimmst.

Grüße
sylo


----------



## KrokoDiehl (27. Jul 2010)

Der Weg über den TreeCellRenderer ist schon gut. Nur musst du im Renderer auf den jeweiligen Knoten zugreifen. In der get-Methode ist der Parameter 
	
	
	
	





```
value
```
der Knoten, der aktuell gerendert werden soll, also dein Report-Objekt. Abhängig von diesem Wert musst du dein Icon bestimmen, dann sollte jeder Knoten im Baum das entsprechende Icon haben. 
In Code sieht das etwa so aus:

```
@Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean selected, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {
 
        super.getTreeCellRendererComponent(tree, value, selected, expanded,
                leaf, row, hasFocus);
 
        // von mir erdacht, kA was dein TreeModel als Objekt (tree node) zurückliefert
        ReportObject reportObj = (ReportObject) value;
        setIcon( reportObj.getIcon() );
 
        return this;
    }
```


----------



## DStrohma (27. Jul 2010)

Ok, habs jetzt hinbekommen. Mein Renderer sieht jetzt so aus:

```
public class ReportCellRenderer extends DefaultTreeCellRenderer {

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

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

        Object nodeObj = ((DefaultMutableTreeNode) value).getUserObject();

        if (nodeObj instanceof ReportTemplate) {
            setIcon(((ReportTemplate) nodeObj).getIcon());
        }

        return this;
    }
}
```

Geht soweit also alles, nur seh ich das richtig dass es keine eigene Methode setIcon oder ähnliches für eine Node (also DefaultMutableTreeNode) gibt?? Sobald ich verschiedene Icons haben will brauch ich einen eigenen Renderer?? Kann mir diesen Mangel jemand schlüssig erklären?


----------



## Michael... (27. Jul 2010)

DStrohma hat gesagt.:


> Sobald ich verschiedene Icons haben will brauch ich einen eigenen Renderer?? Kann mir diesen Mangel jemand schlüssig erklären?


Worin siehst Du da einen Mangel? 
Per 
	
	
	
	





```
setLeafIcon(...)
```
 sagst Du nur mit welchem Icon der Renderer die "Blätter" zeichnen soll, das hilft ihm noch lange nicht die einzelnen Knoten zu unterscheiden. (Der Standard Renderer unterscheidet nur zwischen "Ast" und "Blatt")


----------



## DStrohma (27. Jul 2010)

Naja, der Mangel ist aus meiner Sicht der, dass ich nicht einfach machen kann: 
	
	
	
	





```
node.setIcon(...)
```
. Das wäre doch das einfachste. Weil wenn ich jetzt nicht immer nur Objekte ein und der selben Klasse in den Baum laden würde, dann gebe es wohl auch keine 
	
	
	
	





```
getIcon()
```
 Methode für die Objekte. Wie mach ich das dann. Dann kann ich im Renderer für eine Node kein Icon setzen wenn ich nicht weiß welches Objekt da drin ist...


----------



## Michael... (27. Jul 2010)

Du könntest ja einen eigenen Knoten so definieren. Müsstest allerdings auch einen passenden CellRenderer dazu schreiben, der mit solchen Objekten umgehen kann.

Ich weiss nicht, ob Dir das Renderer Konzept in Swing klar ist?
Du musst ja unterscheiden zwischen dem logischen Objekt (z.B. DefaultMutableTreeNode) und dessen graphischer Darstellung.
Wie so ein Objekt in z.B. einem JTree aussiehst/dargestellt wird, hängt davon ab was für ein Bildchen der Renderer - aufgrund dessen Informationen über das Objekt - zeichnet. Was man als Knoten im JTree sieht ist ja nicht das Objekt selbst, sondern nur seine Abbildung, erzeugt nach den im Renderer festgelegten Regeln.
Bei JTree ist es -glaube ich so - das für alle Knoten ein Renderer verwendet wird.
Bei JTable kann man für unterschiedliche Objekttypen unterschiedliche Renderer definieren.


----------



## DStrohma (27. Jul 2010)

Das hat mich eben etwas verwundert, weil ich bei JTable für jede Spalte einen Renderer setzen kann. Bei einem JTree hätte ich ursprünglich gedacht dass es für jede Node geht. Ok, dann hab ich das jetzt alles kapiert 
DANKE!


----------

