# JPanel geht über Rand hinaus



## Schmuggler (16. Mrz 2010)

Hallihallo,
habe ein Problem mit JPanels.
Das JPanel, welches über den Rand hinaus exisitiert, sollte eigentlich im CENTER des inneren
BorderLayouts liegen, jedoch stimmt das ja irgendwie nicht.
Ich habe schon versucht an allen möglichen Stellen pack() einzufügen, was leider auch nichts geändert hat.
Da mein Projekt recht unübersichtlich mit unterschiedlichen Klassen, die zur Oberfläche beitragen (jeweiliger Teil wird als return JPanel im Endeffekt in die mainGUI gesetzt) weiß ich nicht so recht, was ich davon posten soll, deshalb erst Mal nur ein Foto 
Ich hoffe ihr könnt mir helfen... würd mich freuen 
lg Schmuggler


----------



## hansmueller (16. Mrz 2010)

Hallo, 

GUI-Programmierung kann eine komplizierte Sache sein.
Und ohne einen Fetzen Code, nur mit einem Bild kann man nur sehr schlecht eine Fehleranalyse machen.
Das ist dann mehr so was wie ein ins Blaue hinein raten.

Mein Rateversuch:
Ich vermute, daß du dem JFrame "Bla" eine feste (Fenster-)Größe zugeordnet hast (z. B. mit .setBounds()).
Nimm es heraus, dann sollte es mit .pack() funktionieren. Setze das .pack() bevor du das JFrame sichtbar machts.

MfG
hansmueller


----------



## Schmuggler (16. Mrz 2010)

Vielen Dank schon mal, hab leider gerade keine Zeit um die richtigen Stellen Code zu posten...
Werd ich aber nachholen...


----------



## L-ectron-X (16. Mrz 2010)

Könnte auch ne Mischung von AWT und Swing sein.


----------



## Schmuggler (17. Mrz 2010)

Hier der Code hoffentlich ausreichend ausgewählt zum Verständnis
Main-GUI:

```
import java.awt.*;

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


public class GUI extends JFrame {
	 // Anfang Attribute
	  
	  // Layout
	private JPanel rahmen = new JPanel(new GridLayout(6,1));
	private JPanel zweiteSchicht = new JPanel(new BorderLayout());// in dessen CENTER tritt der Fehler auf
	private JPanel innenButtons = new JPanel(new GridLayout(8,1)); // die Buttons am WEST des zweiteSchicht
	private JPanel main = new JPanel();
	     
	     
	  // Buttons & Labels
	// Rahmen
	private JButton logo = new JButton("Logo");
	private JButton haus = new JButton("Haus");
	private JButton kommunikation = new JButton("Kommunikation");
	private JButton organisation = new JButton("Organisation");
	private JButton www = new JButton("WWW");
	private JButton einstellungen = new JButton("Einstellungen");
	
	// zu Haus
		private JButton back = new JButton("Back");
		private JButton hausinnen = new JButton("Innen");
		private JButton hausaußen = new JButton("Außen");
		private JButton sicherheit = new JButton("Sicherheit");
		
		// Zum Testen
		JPanel test = new JPanel();
		
	     
	  // Ende Attribute

	  public GUI(String title, Ctrl c) {
	    // Frame-Initialisierung
	    super(title);
	    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	    int frameWidth = 800;
	    int frameHeight = 600;
	    setPreferredSize(new Dimension(frameWidth, frameHeight));
	    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
	    int x = (d.width - getSize().width) / 2;
	    int y = (d.height - getSize().height) / 2;
	    setLocation(x, y);
	    Container cp = getContentPane();
	    cp.setLayout(new BorderLayout());
	    // Layout aufbauen
	    cp.add(rahmen, BorderLayout.WEST);
	    cp.add(zweiteSchicht, BorderLayout.CENTER);
	    
	    zweiteSchicht.add(main, BorderLayout.CENTER); // in main spielt sich am Ende alles ab also auch der Fehler
	    	
	    main.setBackground(Color.BLUE);
	    // Buttons für Navigation anbringen
	    	rahmen.add(logo);
	    	rahmen.add(haus);
	    	rahmen.add(kommunikation);
	    	rahmen.add(organisation);
	    	rahmen.add(www);
	    	rahmen.add(einstellungen);

	    // Buttons für Innen
	    	  innenButtons.add(back);
			  innenButtons.add(hausinnen);
			  innenButtons.add(hausaußen);
			  innenButtons.add(sicherheit);
	    	
			  // Anfang Komponenten
	    	
	    	
	    	
	    	// ActionListener
	    	haus.addActionListener(c);
	    	haus.setActionCommand("Haus");
	    	back.addActionListener(c);	    	
	    	back.setActionCommand("Back1");
	    	
	    	hausinnen.addActionListener(c);
	    	hausinnen.setActionCommand("Innen");
	    
	    



	    // Ende Komponenten

	    setResizable(true);
	    pack();
	    setVisible(true);

	  }

	  // Anfang Methoden
	  public void clickHaus(){ // innere Buttonleiste vom Bild wird mit click auf Button Haus geöffnet
		  zweiteSchicht.add(innenButtons, BorderLayout.WEST);
		  zweiteSchicht.setOpaque(false);
		  innenButtons.setVisible(true);
		  /*innenButtons.add(back);
		  innenButtons.add(hausinnen);
		  innenButtons.add(hausaußen);
		  innenButtons.add(sicherheit);*/
		  pack();
		  setVisible(true);
		  
	  }
	  
	  public void clickBack1(){ // auf Back verschwindet alles was die Zeit über aufgebaut wurde nur noch 						//Randnavigation zu sehen
		  zweiteSchicht.remove(main);
		  innenButtons.setVisible(false);
		  main = new JPanel();
		  zweiteSchicht.add(main,BorderLayout.CENTER);
		  main.setBackground(Color.BLUE);
		  main.setVisible(true);
		  pack();
		  setVisible(true);
		  
	  }
	  
	  public void setMain(JPanel p) // hier wird über den Methodenaufruf aus der Klasse Innen heraus die Hauptseite 					// gesetzt
	  {	  zweiteSchicht.add(main, BorderLayout.CENTER);
	  	pack();
	  	main.add(p);		 
		  pack();
		  p.setVisible(true);
		  pack();
		  setVisible(true);
	  }

	  // Ende Methoden


	}
```

Klasse Innen

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




public class Innen implements ActionListener{
	private Raum[] raeume;
	private JPanel p;		// JPanel welches diese Klasse füllz
	private GUI window;		// setMain aus GUI setzt dann JPanel
	// GUI Spezial
	private JPanel buttons = new JPanel(new GridLayout(1,8));
	private JButton add = new JButton("Neuer Raum");
	private JButton[] clickRaum;
	
		
	private boolean loadWindow; // um Teil im Fenster korrekt wiederzugeben, nur damit Backbutton korrekt funktioniert
	
	public Innen(GUI window){
		//raeume = new Raum[0];
		// zu Test zwecken
		raeume = new Raum[4];
		raeume[0] = new Raum("Hause");
		raeume[1] = new Raum("Bla");
		raeume[2] = new Raum("Jaha");
		raeume[3] = new Raum("Test");
		//
		
		clickRaum = new JButton[raeume.length];
		for (int i =0; i< clickRaum.length;i++)
			clickRaum[i] = new JButton(raeume[i].getName());
		this.window = window;
		
		loadWindow = false;
	}
		

	
public void createWindow(){
	if (loadWindow == false)
		{
		p = new JPanel(new BorderLayout());
		p.add(buttons, BorderLayout.NORTH);
		buttons.add(add);
		add.addActionListener(this);
		add.setActionCommand("add"); 
		if (gefuellt <=7){
			for (int i =0; i<6;i++)
			{	if (i<clickRaum.length){
				buttons.add(clickRaum[i]);}
			else buttons.add(new JLabel());
			}
		}
			loadWindow = true;
		}
		if (raeume.length >0){
		p.add(raeume[0].makeWindow(), BorderLayout.CENTER); // zunächst mal geht es nur um die Darstellung des 											//ersten verfügbaren Raumes, makeWindow erzeugt ein  									// JPanel welches zurückgegeben wird
		p.setVisible(true);
		window.setVisible(true);}
		window.pack();
		window.setMain(p); 			// hier wird das gerade erzeugte JPanel ins Hauptfenster eingefügt
	
}


public void setUnseen(){ // dient auch nur dem Backbutton
		loadWindow = false;
	}

}
```

Klasse Raum

```
import java.awt.GridLayout;

import javax.swing.*;

public class Raum{
	private String name;
	private Geraet[] geraet;
	
	public Raum(String name){
		this.name = name;
		geraet = new Geraet[1];
		geraet[0] = new undimmedGeraet("undimmedGeraet"); // Einfügen nur um zu Testen obs geht
	}
	public String getName(){
		return name;
	} 
	
	public JPanel makeWindow(){
		JPanel p = new JPanel(new GridLayout(geraet.length,1));
		if (geraet.length >0){
			for (int i =0; i< geraet.length;i++)
			{
				p.add(geraet[i].createOutline());   // und jetzt wird aus den einzelnen Geräten, wenns dann 									//mal mehrere gibt die spezielle Realisierung 											//rausgeholt werden und eingefügt gleiche Strategie 									//mit JPanel zurückgeben
				p.setVisible(true);
			}
		}
		return p;
	}
	
}
```

Klasse undimmedGeraet Es existiert noch ein Interface was aber für die GUI denk ich nicht relevant ist


```
import java.awt.GridLayout;
import java.io.IOException;
 
import javax.swing.*;


public class undimmedGeraet implements Geraet {

	private String name;
	// Outline
	private JButton on = new JButton("on");
	private JButton off = new JButton("off");
	private JLabel nameIn = new JLabel();
	
	public undimmedGeraet(String name){
		this.name = name;
		
		nameIn.setText(name);
	}

	
	public String getName() {
		// TODO Auto-generated method stub
		return name;
	}

	
	public JPanel createOutline(){
		JPanel x = new JPanel(new GridLayout(1,3));
		x.add(nameIn);
		x.add(on);
		x.add(off);
		x.setVisible(true);
		return x;
	}

}
```

Danke nochmal fürs drüber schauen


----------



## hansmueller (17. Mrz 2010)

Mmmh, ziemlich... umständlich. Aber wie heißt es so schön:
Warum einfach, wenn man es auch kompliziert machen kann?

Kommentier mal die Zeilen 44 bis 46 aus deiner Main-Gui aus:
[JAVA=44]
int frameWidth = 800;
int frameHeight = 600;
setPreferredSize(new Dimension(frameWidth, frameHeight));
[/code]
Somit wird sichergestellt, daß der Layoutmanager nicht an irgendwelche Größenangaben festhält.

Und setze folgenden Abschnitt
[JAVA=48]
int x = (d.width - getSize().width) / 2;
int y = (d.height - getSize().height) / 2;
setLocation(x, y);
[/code]
hinter pack() also nach Zeile 94.
[JAVA=94]
pack();
[/code]

Dann sollte sich das Fenster dem Inhalt anpassen. (Hoffe ich zumindest)

MfG
hansmueller


----------



## Marco13 (17. Mrz 2010)

~"Premature optimization is the root of all evil" (so ungefähr hat D. Knuth das gesagt). Das stimmt aber so nicht. Durch verfrühte Optimierungen werden viele unschöne Dinge verursacht. Aber ich postuliere: Den größen Mist macht man, wenn man versucht, schnell einen Fehler zu beheben, dessen Ursache man nicht kennt. 

Also... die ganzen pack()s und setVisible(true)s kannst du mal rausnehmen. Das einzige, was da EINmal gepackt und visble gemacht werden muss, ist der Frame. Und das ganz am Ende, wenn alles fertig gebaut ist.

Die Liste der GUI-Elemente in "GUI" sieht zwar auf den ersten Blick (und auch in bezug auf die Variablennamen und so) gar nicht sooo unübersichtlich aus, aber ob jetzt zu dem "innenButtons"-Panel 7,8 oder 9 buttons Hinzugefügt werden, und ob vielleicht irgendwo zwei Components an die gleiche Stelle von irgendeinem BorderLayout gelegt werden, kann man am gegebenen Code (praktisch natürlich schon, aber sehr) schlecht nachvollziehen. Sowas KANN(!) aber die beschriebenen Effekte verursachen.

Ansonsten würde ich dir _dringend_ empfehlen, keine überflüssigen Instanzvariablen in der Klasse rumlungern zu haben. Es gibt nur sehr selten einen Grund, wirklich ein [c]private JPanel somePanel[/c] zu haben. 
Ganz subjektiv (!!!) finde ich zum Aufbau von GUIs eine Aufteilung in (private) Methoden und ggf. Klassen ganz praktisch. Wenn man eine "Komplexere" GUI-Klasse hat, die vielleicht sogar eine eigene Entität in einem Datenmodell repräsentiert, kann man dafür eine eigene Klasse erstellen. Ansonten finde ich (nochmal: GANZ subjektiv) den Aufbau des GUIs in einer Hierarchie von Methodenaufrufen, die die grobe Aufteilung des GUI wiederspiegeln, am übersichtlichsten:


```
class GUI extends JFrame
{
    void init()
    {
        Container cp = getContentPane();
        cp.setLayout(new BorderLayout());
        cp.add(createButtonPanel(), BorderLayout.WEST);
        cp.add(createMainControlPanel(), BorderLayout.CENTER);
    }

    private JPanel createButtonPanel()
    {
        JPanel buttonPanel = new JPanel(new GridLayout(1,3)); // Wird nur hier lokal benötigt!
        buttonPanel.add(someButton0);
        buttonPanel.add(someButton1);
        buttonPanel.add(someButton2);
        return buttonPanel;
    }

    private JPanel createMainControlPanel()
    {
        JPanel mainControlPanel = new JPanel(new BorderLayout()); // Wird nur hier lokal benötigt!
        mainControlPanel.add(createDefaultControlPanel(), BorderLayout.NORTH);
        mainControlPanel.add(createOtherControlPanel(), BorderLayout.NORTH);
        return mainControlPanel;
    }
    private JPanel createDefaultControlPanel() { .... }

    private JPanel createOtherControlPanel() { .... }

    ...
}
```


Aber das kann man sehen, wie man will 


EDIT: Der Fehler, der sich in diesem Pseudocode-Beispiel eingeschlichen hat, bleibt jetzt mal drin - als Beispiel dafür, dass man ihn recht schnell findet


----------



## Schmuggler (17. Mrz 2010)

Also, leider hab ich meinen ersten Poste iwie wieder gelöscht naja...
deshalb...
Vielen Dank also schon Mal nochmal 
also wenn ich Zeile 44 bis 46 auskommentiere behebt sich das Problem zwar, aber leider 
ist das Fenster immer nur gerade so groß wies unbedingt sein muss, damit alles sichtbar ist,
das wollte ich eigentlich nicht, deshalb löst das zwar das Problem aber halt nur naja nicht so ganz.
Zumindest ist das Bild mit Verschiebung der Positionierung auch jetzt in der Mitte 
nunja sonst reduzieren von pack und setVisible hat auch nichts geändert...

Ich überdenke jetzt noch einmal mein Konzept und melde mich, falls ich was rausgefunden habe, 
ich denke nämlich, dass das an dem Klasse"gewurschtel" liegt nun denn
lg
Schmuggler


----------

