# JTree Node mit Text plus JComboBox



## hiwi (12. Jul 2010)

Hallo nochmal,
gibt es einen Trick wie man einen Knoten im JTree mit einem Text und daneben mit einer Combobox ausstatten kann? Mit einer Erweiterung des DefaultTreeCellRenderers bin ich da noch nicht auf die richtige Idee gekommen, da dieser ja ein JLabel erweitert und ein JLabel kann unr Text plus Bild (Icon) besitzen. Aber vielleicht gibt es ja noch eine Idee, auf die ich noch nicht gekommen bin. Ein JTableTree finde ich selber nicht so schön, da es zu viel Overhead wäre, optisch gesehen. Also speziell gesagt will ich neben dem Namen des Layouts (zB "meinNeuesLayoutVom12.7.2010") noch ein DropdownMenu (oder Combobox) haben, wo man auswählen kann, welchen Typen (zB "RandomLayout", "CircleLayout" o.ä.) das Layout bekommt. 
Hat irgendwer eine Idee?
Danke!


----------



## Michael... (12. Jul 2010)

Der Renderer stellt nur die Ansicht des Knotens dar. Wenn Du beim Bearbeiten des Knotens eine eigene Komponte verwenden willst: TreeCellEditor. Hab's selbst noch nicht ausprobiert, kenn's nur von JTable


----------



## hiwi (13. Jul 2010)

das scheint zu klappen. es gibt aber noch probleme.  
fang ich mal mit dem ersten an. vielleicht ergibt sich der rest von selbst, sonst müsste ich nochmal code posten. 
wie komme ich im

```
getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row)
```
daran, wo ich mich gerade befinde im Baum? Also ich will if-abfragen machen, wenn der knoten über diesem Knoten "Layouts" heißt, bzw das UserObject ein String namens "Layouts" ist, dann erstelle die Zelle so, und wenn sie 2 darunter ist, dann erstelle sie so...
Danke nochmal


----------



## KrokoDiehl (13. Jul 2010)

Ohne es nun 100%ig zu wissen; Aber das übergebene 
	
	
	
	





```
Object value
```
 dürfte doch der _TreeNode _des Baumes sein? In dem Fall kannst du es casten und über 
	
	
	
	





```
getParentNode()
```
 (oder so ) den Elternknoten suchen.
Ansonsten hast du den _JTree _und den _rowIndex_, da müsste doch sicher auch was gehen, wenngleich es umständlicher wird.


----------



## hiwi (13. Jul 2010)

KrokoDiehl hat gesagt.:


> Ohne es nun 100%ig zu wissen; Aber das übergebene
> 
> 
> 
> ...


Das mit dem value und dem casten war auch meine erste Idee. Das hat nciht funktioniert. Wobei,..., ich hab es glaub ich zum DefaultMutableTreeNode gecastet. Vll sollte ich es nochmal versuchen mit dem TreeNode. Mach ich morgen. Danke schonmal. Ich schreib dann ob es funktioniert hat.


----------



## Michael... (13. Jul 2010)

In 
	
	
	
	





```
value
```
 steckt schon der Knoten, kannst ja mal schauen was Dir 
	
	
	
	





```
System.out.println(value.getClass());
```
 liefert.


----------



## hiwi (16. Jul 2010)

KrokoDiehl hat gesagt.:


> Ohne es nun 100%ig zu wissen; Aber das übergebene
> 
> 
> 
> ...


Das klappt. Danke! 
Zum nächsten Problem. ;-) Ich bin jetzt glaub ich dahintergekommen was der Editor ist. Und das ist nicht wirklich das, was mein Chef haben will. 
Ich habe es jetzt so gemacht, dass ich bei der getTreeCellRendererComponent()-methode im Renderer nicht "this" zurückgebe, sondern eben ein JPanel mit einem JLabel und einer JComboBox drauf. Das anzeigen klappt auch. nur kann ich auf die ComboBox nicht zugreifen. :-( Sie reagiert nicht. Ist jetzt halt als wenn die ComboBox als Bild auf der Zelle ist, ohne Funktion. Hat irgendwer eine Idee? Vielleicht sollte ich das nochmal einzeln posten.
Danke für Hilfe!
hiwi


----------



## Michael... (16. Jul 2010)

hiwi hat gesagt.:


> ein JPanel mit einem JLabel und einer JComboBox drauf. Das anzeigen klappt auch. nur kann ich auf die ComboBox nicht zugreifen. :-( Sie reagiert nicht. Ist jetzt halt als wenn die ComboBox als Bild auf der Zelle ist, ohne Funktion.


Was Du da beschreibst ist genau die Aufgabe des Renderers ein "Bild" zu erzeugen, dass als Knoten angezeigt wird.
Wenn Du editieren willst brauchst Du einen TreeCellEditor. Kann Dir aber mangels persönlicher Erfahrung nicht sagen wie man damit umgeht.


----------



## KrokoDiehl (16. Jul 2010)

Es klingt jedenfalls so, als würde der Editor nichts mit den Events machen können. Für den _JTree _kommt ja ein _JPanel _als Editor zurück. Ich denke dass Mausklicks etc. irgendwie vergereicht werden müssen. Du kannst ja mal einen einfachen _MouseListener _an deinen _JPanel _hängen und Testausgaben reinmachen, analog mit der _JComboBox_, allein um zu sehen, ob dort was ankommt.

Andere Sache könnte der Fokus sein. Vielleicht reagiert eine _JComboBox _nicht, wenn sie keinen Fokus hat und vielleicht bekommt ein _TreeCellEditor _keinen Fokus, bzw. das _JPanel _bekommt ihn, sollte ihn aber an die _JComboBox _weiterreichen.


----------



## Michael... (16. Jul 2010)

Da ich keine Lust auf Arbeit hatte: hier mal eine Demo. Die ist nur auf die Schnelle runtergeschrieben und durchaus noch optimierungsfähig und an einer Stelle habe ich ein bisschen getrickst.

```
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.EventObject;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.event.CellEditorListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellEditor;

public class TreeEditorRendererDemo extends JFrame {
	
	public  TreeEditorRendererDemo() {
		String[] values = new String[] {"Bier", "Limo", "Wein", "Wasser"};
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("Getränke");
		root.add(new DefaultMutableTreeNode(values[0]));
		root.add(new DefaultMutableTreeNode(values[0]));
		root.add(new DefaultMutableTreeNode(values[0]));
		
		DefaultTreeModel model = new DefaultTreeModel(root);
		JTree tree = new JTree(model);
		tree.setCellRenderer(new ComboRenderer(new NodeComponent(values)));
		tree.setCellEditor(new ComboEditor(tree, new NodeComponent(values)));
		tree.setEditable(true);
		this.getContentPane().add(tree);
	}
	
	class NodeComponent extends JPanel {
		private JComboBox box;
		
		public NodeComponent(String[] values) {
			this.setLayout(new GridLayout(1, 2));
			add(new JLabel("Auswahl: "));
			add(box = new JComboBox(values));
			box.setBackground(Color.WHITE);
		}
		
		public void setSelectedItem(Object obj) {
			box.setSelectedItem(obj);
		}
		
		public Object getCurrentObject() {
			return box.getSelectedItem();
		}
		
		public void addItemListener(ItemListener listener) {
			box.addItemListener(listener);
		}
	}
	
	class ComboRenderer extends DefaultTreeCellRenderer {
		private NodeComponent nodePanel;
		
		public ComboRenderer(NodeComponent comp) {
			nodePanel = comp;
		}
		
		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);
    		DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
    		if (treeNode.isLeaf()) {
    			nodePanel.setSelectedItem(treeNode.getUserObject());
    			nodePanel.setBackground(super.getBackground());
    			return nodePanel;
    		}
    		this.setIcon(null);
    		return this;
    	}
	}
	
	class ComboEditor implements TreeCellEditor, ItemListener {
		private JTree tree;
		private NodeComponent nodePanel;
		
		public ComboEditor(JTree tree, NodeComponent comp) {
			this.tree = tree;
			this.nodePanel = comp;
			this.nodePanel.addItemListener(this);
		}
		
		public void itemStateChanged(ItemEvent e) {
			tree.stopEditing();
		}
		
		public Component getTreeCellEditorComponent(JTree tree, Object value,
				boolean isSelected, boolean expanded, boolean leaf, int row) {
    		DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
    		if (treeNode.isLeaf()) {
    			nodePanel.setSelectedItem(treeNode.getUserObject());
    			return nodePanel;
    		}
    		return tree.getCellRenderer().getTreeCellRendererComponent(tree, value, true, true, false, row, true);
		}

		public Object getCellEditorValue() {
			return nodePanel.getCurrentObject();
		}
		
		public boolean isCellEditable(EventObject anEvent) {
			return true;
		}
		
		public void addCellEditorListener(CellEditorListener l) {}
		public void cancelCellEditing() {}
		public void removeCellEditorListener(CellEditorListener l) {}
		public boolean shouldSelectCell(EventObject anEvent) {return false;}
		public boolean stopCellEditing() {return true;}		
	}
	
	public static void main(String[] args) {
		JFrame frame = new TreeEditorRendererDemo();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
```


----------



## hiwi (19. Jul 2010)

Michael... hat gesagt.:


> Da ich keine Lust auf Arbeit hatte: hier mal eine Demo. Die ist nur auf die Schnelle runtergeschrieben und durchaus noch optimierungsfähig und an einer Stelle habe ich ein bisschen getrickst.


Wow, vielen Dank! Das ist großartig! So sollte es aussehen. Ich meine von dieser einen Funktionalität her. Aber das war ja das Problem. Ich werd es bei mir einbauen. Vielen, vielen Dank!!


----------

