# JTabbedPane per Menuitem erstellen



## plammy (15. Jul 2012)

Hallo 
Ich hab folgendes Problem: Ich erstelle per MenuItem Neu... ein JPanel, der sich in einem scrollable TabbedPane befindet. Ich will, dass jedes mal wenn ich auf Neu.. drücke ein zusätzliches JTabbedPane neben den schon bestehenden hinzugefügt wird. Im Moment erscheint aber immer nur ein. Ich will das quasi wie bei Photoshop oder ähnliche Programme, dass wenn man neue Datei erstellt sich immer wieder ein neuen Tab öffnet wo man arbeiten kann.


```
public class GUI extends JFrame implements ActionListener {

 
    /**
     * Erstelle neue GUI
     */
    public GUI() {

        initComponents();   

        setTitle("Layout Tool");
        setSize(900,980);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
       
    }

 public void initComponents() {
        menubar = new JMenuBar();
        menuFile = new JMenu();
        neu = new JMenuItem();

        neu.setMnemonic(KeyEvent.VK_N);
        neu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
        neu.setText("Neu");
        neu.addActionListener(this);
        menuFile.add(neu);
....
}
    public void actionPerformed(ActionEvent object) {
       
        
        //Neu
        if (object.getSource() == neu){     
             CreateFile create = new CreateFile();   
             create.addTabbedPane();
             setContentPane(create);    
             setVisible(true);
        }
.....
```


```
public class CreateFile extends JPanel implements ActionListener
{
 public CreateFile()
    {
        initComponents();    
        buildLayout();
    }

 public void addTabbedPane(){
        scrollPane.setViewportView(editPanel);
        tabbedPane.addTab("Tab "+this.COUNTER ,scrollPane);
        this.COUNTER++;
    }

 public void buildLayout(){
        buildWebsitePanel();
        buildLayoutPanel();
        buildfixFormsPanel();
        buildIndividualFormsPanel();
        buildOrangeFormsPanel();
        buildEditPanel(); 
        buildHolePanel();
    } 

...

 public void buildHolePanel(){

        GroupLayout layout = new GroupLayout(this);
        this.setLayout(layout);
        this.setBackground(darkGray);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
              
                .addComponent(tabbedPane, GroupLayout.DEFAULT_SIZE,0, Short.MAX_VALUE)
                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
                    .addComponent(websitePanel, GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(layoutPanel, GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(fixFormsPanel, GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(individualFormsPanel, GroupLayout.DEFAULT_SIZE,0, Short.MAX_VALUE)
                    .addComponent(orangeFormsPanel, GroupLayout.DEFAULT_SIZE,0, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(20 , 20, 20)
                .addComponent(websitePanel)
                .addGap(18, 18, 18)
                .addComponent(layoutPanel)
                .addGap(18, 18, 18)
                .addComponent(fixFormsPanel)
                .addGap(18, 18, 18)
                .addComponent(individualFormsPanel)
                .addGap(18, 18, 18)
                .addComponent(orangeFormsPanel)
                .addContainerGap())
                
            .addComponent(tabbedPane)            
        );  
    
    }
```


----------



## L-ectron-X (15. Jul 2012)

Habe deinen Code nur überflogen.
Kann sein, dass du noch 
	
	
	
	





```
validate();
```
 aufrufen musst, damit die Oberfläche neu gezeichnet wird.


----------



## plammy (15. Jul 2012)

hmm... immer noch kein Effekt..


----------



## L-ectron-X (15. Jul 2012)

Gut, dann hier mal ein Beispiel:

```
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TabbedAdder implements ActionListener {
  private JTabbedPane pane;
  private JMenuItem fileMenuItem;
  
  public TabbedAdder() {
    JFrame frame = new JFrame("JTabbedPane - Tabs hinzufügen");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setLocationRelativeTo(null);
    frame.setJMenuBar(createTheMenuBar());
    frame.add(createThePane());
    frame.setVisible(true);
  }
  
  private JTabbedPane createThePane() {
    pane = new JTabbedPane();
    return pane;
  }
  
  private JMenuBar createTheMenuBar() {
    JMenuBar bar = new JMenuBar();
    JMenu file = new JMenu("Datei");
    fileMenuItem = new JMenuItem("Neu");
    fileMenuItem.addActionListener(this);
    file.add(fileMenuItem);
    bar.add(file);
    return bar;
  }
  
  public void actionPerformed(ActionEvent e) {
    pane.add("Unbenannt-"+(pane.getTabCount()+1), new JPanel());
    pane.setSelectedIndex(pane.getTabCount()-1);
  }
    
  public static void main(String[] args) {
    TabbedAdder ta = new TabbedAdder();
  }
}
```


----------



## plammy (15. Jul 2012)

Ich habs versucht das in meinem Code umzusetzten, aber ich hab anscheinend iwo ein Denkfehler... .. Funktioniert immer noch wie früher





```
public class GUI extends JFrame implements ActionListener {

 
    /**
     * Erstelle neue GUI
     */
    public GUI() {

        initComponents();   

        setTitle("Layout Tool");
        setSize(900,980);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);      
    }
..
 public void actionPerformed(ActionEvent object) {
       
        
        //Neu
        if (object.getSource() == neu){     
              
        CreateFile create = new CreateFile();   
        create.deleteTF();
        create.tabbedPane.add("Tab "+(create.tabbedPane.getTabCount()+1) ,create.scrollPane);
        validate();
        setContentPane(create);    
        setVisible(true);
        }
```



```
public class CreateFile extends JPanel implements ActionListener
{
  public CreateFile()
    {  
        addTabbedPane();
        initComponents();    
        buildLayout();
      
    }
..
  public ClosableTabbedPane addTabbedPane(){
         //Panels 
        tabbedPane = new ClosableTabbedPane();
        
        editPanel = new EditPanel();
        editPanel.setFocusable(true);           
        editPanel.getPreferredSize();

        scrollPane=new JScrollPane();
        scrollPane.setFocusable(true);
        scrollPane.setPreferredSize(new Dimension(600,600));  //sichtbare Größe der ScrollPane 
        
        scrollPane.setViewportView(editPanel);
       
        
        return tabbedPane;
    }
```


----------



## vanny (15. Jul 2012)

> scrollPane.setPreferredSize(new Dimension(600,600));  //sichtbare Größe der ScrollPane



ist schonmal ein zeichen für ein schlechtes Layoutkonzept.


```
public class DieTabbedPane extends JTabbedPane{
	
	public void neuesTab(String titel, JPanel inhalt){
		this.addTab(titel, inhalt);
	}

}
```
...sollte eigentlich all das tun, was du wolltest.
Ein validate(); hab ich bisher nie benötigt.

Gruß Vanny


----------



## plammy (16. Jul 2012)

tuts aber nicht...  kann es an der Kommunikation zwischen der Klassen liegen??


----------



## plammy (17. Jul 2012)

Kann es sein vllt, dass bei der erstellung immer das alte tabbedPane überschrieben wird ??


----------



## Michael... (17. Jul 2012)

Dein Kontrukt/Klassendesign ist merkwürdig.
Gründsätzlich fragwürdig ist warum, um eine neue Tab hinzuzufügen, jedesmal ein neues Objekt (CreateFile) erzeugt wird, das scheinbar diesen Hinzufügen vornehmen soll?
Auch das Erzeugen einer neuen ClosableTabbedPane Instanz ist merkwürdig - mal abgesehen, davon, dass damit scheinbar nichts gemacht wird. Gründsätzlich stehen im Code - zumindest in dem hier geposteten - viele nutzlose Zeilen.

Allgemein: Definiere eine Klasse, welche die Inhalte der JTabbedPane kontrolliert und das Hinzufügen/Entfernen von Tabs steuert.


----------



## plammy (17. Jul 2012)

ja aber das problem ist dass ich GroupLayout verwende und nicht einfach frame.add(pane) sagen kann...


----------



## Michael... (17. Jul 2012)

plammy hat gesagt.:


> ja aber das problem ist dass ich GroupLayout verwende und nicht einfach frame.add(pane) sagen kann...


Was hat das mit dem GroupLayout und dem Frame zu tun? Es sollen doch während der Laufzeit Tabs in einer bestehenden JTabbedPane hinzugefügt bzw. entfernt werden - und das geht ja direkt an der JTabbedPane mit addTab(...) bzw. removeTabAt(int)


----------



## plammy (18. Jul 2012)

ja aber wo soll ich das denn schreiben??? es geht nicht egal wo ich das mach 



> Allgemein: Definiere eine Klasse, welche die Inhalte der JTabbedPane kontrolliert und das Hinzufügen/Entfernen von Tabs steuert.



Dafür habe ich ja meine Klasse ClosableTabbedPane


```
public class ClosableTabbedPane extends JTabbedPane{
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private TabCloseUI closeUI = new TabCloseUI(this);
        GUI gui = new GUI();
        
    @Override
        public void paint(Graphics g){
                super.paint(g);
                closeUI.paint(g);
        }
        
    @Override
        public void addTab(String title, Component component) {
                super.addTab(title+"  ", component);
        }
        
        
        public String getTabTitleAt(int index) {
                return super.getTitleAt(index).trim();
        }
        
        private class TabCloseUI implements MouseListener, MouseMotionListener {
                private ClosableTabbedPane  tabbedPane;
                private int closeX = 0 ,closeY = 0, meX = 0, meY = 0;
                private int selectedTab;
                private final int  width = 5, height = 5;
                private Rectangle rectangle = new Rectangle(0,0,width, height);
                @SuppressWarnings("unused")
                private TabCloseUI(){}
                
                
                public TabCloseUI(ClosableTabbedPane pane) {
                        
                        tabbedPane = pane;
                        tabbedPane.addMouseMotionListener(this);
                        tabbedPane.addMouseListener(this);
                }
                ....
}
```


----------



## Michael... (18. Jul 2012)

plammy hat gesagt.:


> Dafür habe ich ja meine Klasse ClosableTabbedPane


Bin mir nicht sicher, ob Du Dir mit einer überschriebenden JTabbedPane einen Gefallen tust.

Warum machst Du es nicht erstmal nach dem Prinzip, welches L-ectron-X in seinem Beispiel verwendet und behandelst das Erzeugen und Entfernen von Tabs mit einem externen Listener?


----------



## plammy (18. Jul 2012)

ja ok aber was ist denn falsch in meinem Code?? wo ist der Fehler..?


----------



## Michael... (18. Jul 2012)

plammy hat gesagt.:


> ja ok aber was ist denn falsch in meinem Code?? wo ist der Fehler..?



Grundsätzlich sehe ich da keinen Fehler. Für mich stellt sich alledings die Frage warum ein MouseListener eine paint() Methode hat und wofür das GUI Objekt ist, das hier neu erzeugt wird.


----------



## plammy (18. Jul 2012)

> MouseListener eine paint() Methode hat



was meinst du damit?

Also ich versuchs das ganze neu zu erklären 

Ich habe 2 Klassen: CreateFile und GUI
in GUI werden die Menüs erzeugt und das Startpanel erzeugt. 
Wenn man z.b.der Menüeintrag "New" anklickt, soll einen neuen JPanel an der Stelle von startPanel erzeugt werden, und dieser neuen JPanel wird in CreateFile definiert(also alles was dadrin stehen muss und gezeichnet wird und layout und bla). In diesen neuen JPanel ist auch die JTabbedPane.


----------



## Michael... (18. Jul 2012)

plammy hat gesagt.:


> was meinst du damit?


Das Bezog sich auf die Klasse TabCloseUI, die als Mouse/MotionListener der JTabbedPane registriert wird.
In der überschriebenen paint ( bei Swing Komponenten sollte man besser nach Möglichkeit die paintComponent überschreiben) der TabbedPane wird an einer Instanz dieser Klasse ebenfalls eine paint(Graphics) aufgerufen.

Die andere Sache ist die mit dem GUI Objekt. Wenn ich es richtig verstanden habe, ist (soll) die ClosableTabbedPane im GUI Objekt verbaut (werden). Warum besitzt die TabbedPane dann ein eigenes GUI Objekt? Wenn überhaupt notwendig, dann sollte die TabbedPane vermutlich höchstens eine Referenz auf das bestehende GUI Objekt besitzen?


----------



## plammy (18. Jul 2012)

oh man  ich habs jetzt auch mit den normalen JTabbedPane versucht  nix...

iwo vergesse ich was aber ich weiß nicht wo...



```
public class CreateFile extends JPanel implements ActionListener
{
 public CreateFile()
    {
        initComponents();  
        buildLayout();
        
    }

    public void initComponents() 
    {   
       //Panels 
        tabbedPane = new JTabbedPane();    
        editPanel = new EditPanel();
   }


public void buildHolePanel(){
              
      
        /*   gesamt */ 
        scrollPane.setViewportView(editPanel);
        tabbedPane.addTab("neu    ", scrollPane);
       
        GroupLayout layout = new GroupLayout(this);
        this.setLayout(layout);
        this.setBackground(darkGray);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
              
                .addComponent(tabbedPane, GroupLayout.DEFAULT_SIZE,0, Short.MAX_VALUE)
                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
                    .addComponent(websitePanel, GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(layoutPanel, GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(fixFormsPanel, GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE)
                    .addComponent(individualFormsPanel, GroupLayout.DEFAULT_SIZE,0, Short.MAX_VALUE)
                    .addComponent(orangeFormsPanel, GroupLayout.DEFAULT_SIZE,0, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(20 , 20, 20)
                .addComponent(websitePanel)
                .addGap(18, 18, 18)
                .addComponent(layoutPanel)
                .addGap(18, 18, 18)
                .addComponent(fixFormsPanel)
                .addGap(18, 18, 18)
                .addComponent(individualFormsPanel)
                .addGap(18, 18, 18)
                .addComponent(orangeFormsPanel)
                .addContainerGap())
                
            .addComponent(tabbedPane)            
        );  
      
    public void buildLayout(){
        buildWebsitePanel();
        buildLayoutPanel();
        buildfixFormsPanel();
        buildIndividualFormsPanel();
        buildOrangeFormsPanel();
        buildEditPanel(); 
        buildHolePanel();
    }
```


```
public class GUI extends JFrame implements ActionListener{
 public GUI() {

        initComponents();   

        setTitle("Layout Tool");
        setSize(1050,980);
       
        setLocationRelativeTo(null);

        WindowListener exitListener = new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                closeProgramm();
            }
        };
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(exitListener);
       
    }

public void initComponents() {
         startPanel = new JPanel(){
                public void paint (Graphics g){
                    super.paint(g);

                    g.fillRect(0, 0, startPanel.getWidth() , startPanel.getHeight());
                    g.drawImage(img,startPanel.getWidth()/2-200,startPanel.getHeight()/2-100,null);
           
                }
        };   

        menubar = new JMenuBar();
        menuFile = new JMenu();
        menuAds = new JMenu();
             
        neu = new JMenuItem();
...
}

 public void actionPerformed(ActionEvent object) {
      
        //Neu
        if (object.getSource() == neu){    
        
        CreateFile create = new CreateFile();   
        create.deleteTF();

        saveUnder.setEnabled(true);
        setContentPane(create);    
        setVisible(true);
           
        }
```


----------



## Michael... (18. Jul 2012)

Auch hier wieder das "Phänomen" der Neuerstellung von Objekten.

Warum wird bei jedem Klick auf den MenuItem "neu" eine neues Objekt "CreateFile" und somit ein neues JTabbedPane erzeugt?

Es sieht so aus, als weißt Du nicht wie Du Referenzen auf bestehende Objekte übergeben sollt und erstellst, damit der Code überhaupt kompiliert einfach neue Objekte.


----------



## plammy (18. Jul 2012)

ich weiß nur  dass ich die sonst static machen muss .. abe rich wollt eeig nicht


----------



## Michael... (18. Jul 2012)

plammy hat gesagt.:


> ich weiß nur  dass ich die sonst static machen muss .. abe rich wollt eeig nicht


Static wäre ja auch der falsche Weg. Java arbeitet mit Objekten und wenn man den Zugriff auf bestimmte Objekte tatsächlich in anderen Klassen benötigt, muss man eben eine Referenz der Objekte an entsprechender Stelle übergeben.
Wenn Du eine Methode von Objekt A in einem Objekt B aufrufen willst benötigt B eine Referenz auf A.


```
class B {
    private A a;

    public B(A a) {
         this.a = a;
    }

    public void letASayHello() {
         a.sayHello();      
    }
}

class A {
    public void sayHello() {
        System.out.println("Hello");
    }
}

public static void main(String[] s) {
    A a = new A();
    B b = new B(a);
    b.letASayHello();
}
```


----------

