# JTree/ JTabbedPane



## PollerJava (20. Jun 2007)

Hallo,

ich möchte ein Fenster realisieren, so wie es z.B: in NetBeans oder auch im JBuilder aussieht und zwar, wenn ich im JTree auf ein Leaf doppelklicke dann macht sich ein Fenster (bei mir ein JPanel) auf, Ich möchte mehrere Fenster öffnen können (die öffenen Fenster sollen mit einem JTabedPane dargestellt werden)

Meine Frage wäre jetzt, ob es zu realisieren ist, dass ich den JTree zusammenklappe und wenn ich mit der Maus drüber fahre, dass dieser sich öffnet.
Weiters möchte ich bei den Reitern (Tabs) ein Schliessen- Zeichen (X) und einen Icon auf jeden Reiter plazieren.

Ist das Möglich bzw. gibts da schon vorlagen oder irgendwelche Desing- Pattern dafür?
Ich habe die JPanels schon fertig und möchte diese eben wie oben beschrieben darstellen.


herzlichen Dank für Eure Anregungen,


lg
Hannes


----------



## PollerJava (20. Jun 2007)

Weiß da keiner was dazu?


----------



## Beni (20. Jun 2007)

Doppelklick musst du halt mit einem MouseListener abfangen.

Wenn du auch einen MouseMotionListener hinzufügst, wirst du informiert sobald die Maus über dem JTree ist. Der JTree hat Methoden wie "expand...", mit dem man ihn aufklappen kann.

Du kannst eine eigene Component auf ein Tab setzen (und somit alles darstellen, was du willst), siehe "JTabbedPane#setTabComponentAt", das geht aber erst ab Java 1.6.


----------



## André Uhres (20. Jun 2007)

http://www.java-forum.org/de/userfiles/user3690/MTabbedPane.java
http://www.java-forum.org/de/userfiles/user3690/Test.java
http://www.java-forum.org/de/userfiles/user3690/MTabbedTransferable.java


----------



## PollerJava (20. Jun 2007)

SUpppper!!!
Danke!!

Das ist genau das was ich brauche: einziges Problem: ich weiß nicht, wie ich das Icon auf den Tabs darstellen kann:
Wie kann ich die Zeile interpretieren:


```
Icon icon = new Icon icon = new javax.swing.ImageIcon(getClass().getResource("/toolbarButtonGraphics/media/Stop16.gif"));
```


Ich habs mit dieser Zeile versucht aber da wurde leider nichts angezeigt:



```
Icon icon = new ImageIcon(System.getProperty("user.dir") + "\\pics\\bild.png");
```


----------



## PollerJava (20. Jun 2007)

Danke, ich habs schon!!!

Bin a bissl im Stress und überseh ziemlich viel heute.


----------



## PollerJava (20. Jun 2007)

Gibts eigentlich schon was fertiges bzg. JTree und JTabbedPane kombiniert also so wie in Eclipse oder in NetBeans oder JBuilder (links der JTree und wenn ich ein Blatt anklicke, dann macht sich ein Fenster auf.

Ich hab zwar nichts ergooglen können aber das soll ja nichts heißen.


Vielleicht hat ja jemand was, wäre sehr dankbar für einen Tipp, Link, o.ä

lg


----------



## André Uhres (20. Jun 2007)

Hier ein kleines Testprogramm (dazu musste ich MTabbedPane geringfügig anpassen, 
so daß auch ein leeres MTabbedPane gezeichnet wird):

```
package treetab2;
/*
* Test.java
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Test extends JFrame implements MouseListener, MouseMotionListener{
    private MTabbedPane a;
    private JTree tree;
    public Test() {
        super("Test MTabbedPane");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 400);
        setLocationRelativeTo(null);
        tree = new JTree();
        a = new MTabbedPane(Color.WHITE, Color.LIGHT_GRAY);
        JScrollPane s = new JScrollPane();
        s.setPreferredSize(new Dimension(200, 0));
        getContentPane().add(a);
        s.setViewportView(tree);
        getContentPane().add(s, BorderLayout.WEST);
        tree.addMouseListener(this);
        tree.addMouseMotionListener(this);
    }
    public void mouseClicked(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {
        if(e.getClickCount()==2){
            openSelected();
            return;
        }
    }
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    private void openSelected() {
        DefaultMutableTreeNode selectedNode =
                (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        if(selectedNode.isLeaf()){
            openSelectedDocument(selectedNode);
        }
    }
    private void openSelectedDocument(DefaultMutableTreeNode node) {
        for (int i = 0; i < a.getTabCount(); i++) {
            if(a.getTitleAt(i).equals(node.toString())){
                a.setSelectedIndex(i);
                return;
            }
        }
        JPanel panel = new JPanel();
        panel.add(new JLabel(node.toString()));
        a.addTab(node.toString(), panel, MTabbedPane.WITH_CLOSE_CROSS);
        a.setSelectedComponent(panel);
    }
    public void mouseDragged(MouseEvent e) {}
    public void mouseMoved(MouseEvent e) {
        TreePath selectionPath = tree.getClosestPathForLocation(e.getX(), e.getY());
        tree.expandPath(selectionPath);
    }
    public static void main(final String [] args) {new Test().setVisible(true);}
}
```


----------



## PollerJava (21. Jun 2007)

Vielen Dank!! für deine Antworten (sind sehr sehr hilfreich)


darf ich noch fragen, wie ich meine Panels hinzufügen kann und wie ich die einzelenen Knoten einen Namen meiner Wahl geben kann, 
normal schreibt man ja bei der Wurzel : 


```
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Das ist der Name der Wurzel");, 
DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Bild " + i);
        ((DefaultMutableTreeNode) treeModel.getRoot()).add(child1);
```


aber das kann ich nicht finden im Code,


herzlichen Dank für deine Antworten- haben mir sehr geholfen!!!


liebe Grüße


----------



## André Uhres (21. Jun 2007)

PollerJava hat gesagt.:
			
		

> ..wie ich meine Panels hinzufügen kann ..


Wie sind denn deine Panels definiert? Ein wenig mehr musst du schon erzählen,
denn meine Kristallkugel ist immer noch in Reparatur :wink:



			
				PollerJava hat gesagt.:
			
		

> ..und wie ich die einzelenen Knoten einen Namen meiner Wahl geben kann..


In deinem Beispielcode hast du ja schon einen Namen gegeben: "Bild " + i


----------



## PollerJava (21. Jun 2007)

Ich meinte folgendes:


<<<Du erzeugst ja mit dem Code unten den JTree und ich weiß jetzt nicht genau, wie ich die Wurzel, die Knoten und die Blätter benennen kann. Mit dem Beispiel mit "Bild " + i" meinte ich, dass ich es früher mal so Programmiert habe (bzw. so stehts im Java Handbuch), Du programmierste es ja ein bisschen anders. >>>

Ahh jetzt hab ich glaube ich kapiert, ich muss ja meinen Tree erst konstruieren, das von dier ist ja nur ein Default- Tree bzw. root. 


```
tree = new JTree();
        a = new MTabbedPane(Color.WHITE, Color.LIGHT_GRAY);
        JScrollPane s = new JScrollPane();
        s.setPreferredSize(new Dimension(200, 0));
        getContentPane().add(a);
        s.setViewportView(tree);
        getContentPane().add(s, BorderLayout.WEST);
        tree.addMouseListener(this);
        tree.addMouseMotionListener(this);
```


Meine Panels erzeuge ich so wie unten dargestellt und mit mainFrame.add(myPanel) zeige ich die Panels (x Panels) in meinem MeinFrame an. Diese Panels unten sollten eben jetzt in meinem JTree sein. 


```
private void generatePanels()
	{	
	for (int i = 0; i < x; i++)
	    {      
                myPanel.setBounds(10,10, 400, 300);                    
                myPanel.setOpaque(true);                   
                myPanel.setLayout(null);
                myPanel.setBounds(i*200, i*200, 100, 100);	                             
                mainFrame.add(myPanel);          // meine myPanel's möchte ich in dem JTree hinzufügen, mainFrame ist hier bei mir jetzt noch mein JFrame
            }
        }
```


herzlichen Dank für Deine Hilfe!!

lg


----------



## PollerJava (21. Jun 2007)

Vielen dank André, es hat sich einiges gelichtet, Ich habs jetzt verstanden!


herzlichen dank!!


lg


----------



## PollerJava (21. Jun 2007)

Hallo,

ich hab von Andre diese Klasse bekommen und möchte den JTree einblenden, wenn ich mit der Maus an den linken Rand fahre. Wenn ich dann mit der Maus aus der aktuellen Größe des JTree fahre, soll er wieder verscheinden. Ich habs schon mit mouseEntered() (s.setPreferredSize(new Dimension(200, 0)) und mouseExited s.setPreferredSize(new Dimension(15, 0)) versucht aber das Problem ist, dass der MouseListener nur auf die 15Pixel reagiert und nicht wenn ich den JTree eben 200 Pixel breit mache, auf die 200.

Es soll auch das Panel für die Taps unter dem JTree sein bzw. wenn sich der JTree verkleinert soll sich das JPanel vergrößern.

Vielleicht kann mir da jemand einen Tip geben wie das am besten zu realisieren ist.

herzlichen Dank

lg 



```
package treetab2;
/*
* Test.java
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Test extends JFrame implements MouseListener, MouseMotionListener{
    private MTabbedPane a;
    private JTree tree;
    public Test() {
        super("Test MTabbedPane");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 400);
        setLocationRelativeTo(null);
        tree = new JTree();
        a = new MTabbedPane(Color.WHITE, Color.LIGHT_GRAY);
        JScrollPane s = new JScrollPane();
        s.setPreferredSize(new Dimension(200, 0));
        getContentPane().add(a);
        s.setViewportView(tree);
        getContentPane().add(s, BorderLayout.WEST);
        tree.addMouseListener(this);
        tree.addMouseMotionListener(this);
    }
    public void mouseClicked(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {
        if(e.getClickCount()==2){
            openSelected();
            return;
        }
    }
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    private void openSelected() {
        DefaultMutableTreeNode selectedNode =
                (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        if(selectedNode.isLeaf()){
            openSelectedDocument(selectedNode);
        }
    }
    private void openSelectedDocument(DefaultMutableTreeNode node) {
        for (int i = 0; i < a.getTabCount(); i++) {
            if(a.getTitleAt(i).equals(node.toString())){
                a.setSelectedIndex(i);
                return;
            }
        }
        JPanel panel = new JPanel();
        panel.add(new JLabel(node.toString()));
        a.addTab(node.toString(), panel, MTabbedPane.WITH_CLOSE_CROSS);
        a.setSelectedComponent(panel);
    }
    public void mouseDragged(MouseEvent e) {}
    public void mouseMoved(MouseEvent e) {
        TreePath selectionPath = tree.getClosestPathForLocation(e.getX(), e.getY());
        tree.expandPath(selectionPath);
    }
    public static void main(final String [] args) {new Test().setVisible(true);}
}
```


----------



## André Uhres (21. Jun 2007)

PollerJava hat gesagt.:
			
		

> ..möchte den JTree einblenden, wenn ich mit der Maus an den linken Rand fahre.
> Wenn ich dann mit der Maus aus der aktuellen Größe des JTree fahre, soll er wieder verscheinden...


Hab's jetzt mal hier so angepasst: http://www.java-forum.org/de/viewtopic.php?p=306300#306300
(zusätzlich sind die Tabs verschiebbar)


----------



## PollerJava (22. Jun 2007)

Vielen Dank Andre!!!!


lg


----------



## PollerJava (22. Jun 2007)

Hallo nochmal,


ich hätte noch zwei Fragen und zwar erstens, wie ich verschiedene Icons auf die Leafs eines JTrees bekomme und zweitens möchte ich beim Code oben auswählen können, ob der JTree über das rechte Bild geht oder eben so wie jetzt , dass sich der rechte Bereich verkleinert wenn sich der JTree öffnet,

Hat vielleicht jemand noch einen Tipp für mich bezüglich dieser Problemchen.

herzlichen Dank - is echt super dieses Forum (bzw. natürlich die Leute dahinter)


Momentan setzte ich die Icons für die Leafes so (es hat dann jedes Leaf das selbe Icon, ich möchte aber für jedes Leaf ein anderes Icon): 

```
renderer = (DefaultTreeCellRenderer)tree.getCellRenderer();
            renderer.setOpenIcon(new ImageIcon(System.getProperty("user.dir") + "\\pics\\rotor1.png"));
            renderer.setClosedIcon(new ImageIcon(System.getProperty("user.dir") + "\\pics\\hintergrundBild.png"));     
            renderer.setLeafIcon(new ImageIcon(System.getProperty("user.dir") + "\\pics\\eye.png"));
```


----------



## André Uhres (22. Jun 2007)

PollerJava hat gesagt.:
			
		

> ..erstens, wie ich verschiedene Icons auf die Leafs eines JTrees bekomme..


Du musst einen neuen CellRenderer setzen:

```
tree.setCellRenderer(myRenderer);
```
Dieser CellRenderer könnte so aussehen:

```
class MyTreeRenderer extends DefaultTreeCellRenderer {
    @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
...
        setIcon(...);//deine spezielle Logik muss hier bestimmem, welcher Icon für welchen Node gesetzt wird!
...
        return this;
    }
}
```


----------



## PollerJava (22. Jun 2007)

Wie kann ich das machen bzw. wo rufe ich die Methode getTreeCellRendererComponent auf?
ich habs jetzt mal so wie unten angeführt aufgerufen aber ich weiß nicht ob das passt. Ich muss diese Methode ja für jedes Leaf aufrufen, oder?

Ich steh da ein bissl auf der Leitung.
Vielleicht könntest du mir noch mal ein bisschen weiterhelfen.

Vielen Dank auf jeden Fall!!


lg





```
private MyTreeRenderer myTreeRenderer = new MyTreeRenderer ();


for (int j = 0; j < anzahlChild-1; j++)
                {
                child = new DefaultMutableTreeNode(Control.states.elementAt(offsetChild+j+1).getTypeVarID());
                root.add(child);
                String x = Control.states.elementAt(offsetChild+j+1).getPanel().toString();
                String[] y = x.split(",");  
                for (int k = 0; k <= y.length - 1; ++k)
                    {                   
                    subchild = new DefaultMutableTreeNode(y[k]);
                    child.add(subchild);
                    myTreeRenderer.getTreeCellRendererComponent(tree, this.subchild, true, true, true, 5, true); // ich weiß auch nicht genau, was ich hier übergeben muss,
                    }
                }
```


----------



## André Uhres (22. Jun 2007)

```
...
public class Test extends JFrame implements MouseListener, MouseMotionListener{
...
    private MyTreeRenderer myRenderer;
    public Test() {
...
        myRenderer = new MyTreeRenderer();
        tree.setCellRenderer(myRenderer);
    }
...
}
class MyTreeRenderer extends DefaultTreeCellRenderer {
    private Icon icon1 = new ImageIcon(new ImageIcon(getClass().getResource("Picture1.jpg")).getImage().getScaledInstance(-1,16,0));
    private Icon icon2 = new ImageIcon(new ImageIcon(getClass().getResource("Picture2.jpg")).getImage().getScaledInstance(-1,16,0));
    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
        if(leaf){
//diese Logik musst du anpassen, um für jeden Leaf den Icon zu setzen, den du haben willst:
            if(value.toString().indexOf('1') > 0){
                setIcon(icon1);
            }else{
                setIcon(icon2);
            }
//------------------------------------------
        }
        return this;
    }
}
```


----------



## PollerJava (23. Jun 2007)

Vielen Dank Andre, jetzt gehts endlich bei mir obwohl ich den Programmablauf nicht ganz verstanden haben,

ich mache mir eine Klasse, leite diese von DefaultTreeCellRenderer ab und übergebe das Objekt meines Renderers an die Methode: tree.setCellRenderer(myRenderer); 

aber wer ruft mir die Methode getTreeCellRendererComponent(...) auf, das ist mir nicht ganz klar (das Betriebssystem?)


----------



## André Uhres (23. Jun 2007)

Der CellRenderer wird von der API benutzt um alle Zeilen darzustellen. 
Du kannst dir den CellRenderer als konfigurierbaren Stempel vorstellen,
den der JTree benutzt, um die Daten in jede einzelne Zeile zu stempeln.


----------



## PollerJava (23. Jun 2007)

Vielen Dank Andre für deine SUPER- Antworten, hat mir unendlich viel weitergeholfen und ich hab auch gesehen, dass es über das Java Handbuch von Guido Krüger hinaus noch sehr viel weiteres gibt (kenn das Buch fast auswendig, lese jetzt gerade Java ist auch eine Insel) 

eine Frage hätte ich noch bzg. dem JTree ein und ausklappen, 
vielleicht könntest du mir da noch einen Tipp geben, ich möchte ja, das der JTree entweder das Panel rechts daneben verschiebt oder eben über das rechte Panel drüber geht,

ich habe jetzt das Ganze mit einem JSplitPane realisiert (ist bis auf das JSplitPane genau gleich zu deinem)
kann ich das irgendwie einfach realisieren, dass der JTree (also die linke Seite des JSplittedPane) über die rechte Seite drübergeht,

Ich möchte den Anwender am Anfang fragen, wie er es haben will und da wäre es mir sehr recht, wenn ich nicht viel verändern müsste bzw. wenn ich fast den gleichen Code hernehmen könnte.


herzlichen Dank für deine Antworten!!!

liebe Grüße


----------



## André Uhres (23. Jun 2007)

PollerJava hat gesagt.:
			
		

> ..ich möchte ja, das der JTree entweder das Panel rechts daneben verschiebt oder eben über das rechte Panel drüber geht..


Bei meiner Version wär's einfach:

```
if(JOptionPane.showConfirmDialog(this, "Overlap?") == JOptionPane.YES_OPTION){
            getLayeredPane().add(s, JLayeredPane.POPUP_LAYER);
            s.setBounds(0, 0, 200, 800);
        }else {
            getContentPane().add(s, BorderLayout.WEST);
        }
```
Ansonsten fällt mir jetzt nix dazu ein.


----------



## PollerJava (23. Jun 2007)

Super Andre!!

Vielen herzlichen Dank!!!

lg


----------



## PollerJava (25. Jun 2007)

Hallo nochmal,


Ich hab schon ein bisschen ein schlechtes Gewissen wegen meiner vielen Fragerei aber eine hätte ich noch.
Ich möchte jetzt noch machen, dass man am linken Rand sieht, dass ein Menü vorhanden ist, also wie vielleicht in NetBeans, das eine kleine Leiste am linken Rand ist mit einem Namen und wenn man drauffährt, dass dann der JTree aufklappt.

Hättest du da vielleicht noch einen tipp für mich wie ich das leicht realisieren könnten?


herzlichen dank auf jeden Fall für deine Hilfe.

lg


----------



## André Uhres (25. Jun 2007)

Hab jetzt "Test" und "MTabbedPane" angepasst und neu hochgeladen:
http://www.java-forum.org/de/viewtopic.php?p=306300#306300


----------



## PollerJava (27. Jun 2007)

Hallo Andre,

ich wollte jetzt noch realisieren, dass ich mit einem "Buttondruck" (diesen Button habe ich mir angelegt) alle Tabs schließen kann mir ist aber nicht ganz klar wie ich das lösen kann,

Das Schließen ist ja mit einem Observer- Pattern gelöst, so weit ich das erkannt habe aber ich weiß jetzt nicht was ich aufrufen kann, wenn ich meinen Button (zum Schließen aller Tabs) drücke.

Könntest Du mir da noch einen Hinweis geben.


[add]: ich hab jetzt mal a.removeAll() gemacht und es funktioniert auch, ist das Ok so zu machen oder gibts eine bessere Möglichkeit?


herzlichen Dank wieder mal,

lg


----------



## André Uhres (27. Jun 2007)

Das müsste OK sein, denn "mousePressed" macht ja auch nix anderes als "remove(tabNumber);" zum Schliesen eines Tabs.


----------



## PollerJava (27. Jun 2007)

Hallo Andre nochmal,


könntest Du mir sagen, wo im code von einem Tab auf den anderen umgeschaltet wird oder besser gesagt: wenn ich mit der Maus auf einen anderen Tab klicke, wo der wechsel stattfindet? ich möchte beim wechsel von einem Tab zu einem anderen noch was programmieren.

Vielen vielen Dank

lg


----------



## André Uhres (27. Jun 2007)

http://www.exampledepot.com/egs/javax.swing/tabbed_TpEvt.html


----------



## PollerJava (27. Jun 2007)

Danke vielmals!!


lg


----------



## PollerJava (28. Jun 2007)

Hallo Andre,


ist es möglich, dass man mehrere Wurzeln in einem JTree darstellt bzw. könntest Du mir ungefähr beschreiben, wie das möglich ist?

ich hab schon probiert aber ich bekomme es nicht hin.


lg


----------



## André Uhres (28. Jun 2007)

JTree kann nur einen einzigen Root haben.

Du kannst jedoch den Root Node ausblenden (tree.setRootVisible(false), 
und die Kinder der ersten Ebene als deine "Roots" benutzen.


----------



## PollerJava (28. Jun 2007)

Dankeschön,

genau das habe ich benötigt!!


Danke


----------



## PollerJava (2. Jul 2007)

Hallo Andre,


Ich hätte noch eine Frage (ist aber nicht so wichtig, solltest du keine Zeit/Lust o.ä. haben)

Und zwar, wenn ich so viele Tabs aufmache, dass rechts oben die Naviagationspfeile (< >) erscheinen, um alle Tabs erreichen zu können, dann kann ich, wenn ich mit dem Pfeil nach rechts (>) fahre, keine Tabs mehr schließen,

wenn ich dann mit dem Naviagtionspfeil wieder nach links fahre (<), dann gehts wieder.

Weißt Du da vielleicht eine einfache abhilfe, ansonsten begrenze ich einfach die offenen Tabs.


Und eine zweite Frage hätte ich auch noch, und zwar, kann man die Tabs verkleinern, sodass ich z.B.: 2 oder mehrere Tabs nebeneinander anordnen kann?


herzlichen Dank und lg


----------

