# Component von JPanel mit Null Layout auf JPanel mit FlowLayout verschieben



## TobyNick (26. August 2011)

Hallo,
ich habe ein Problem. Und zwar habe ich einen JButton in einem JPanel (panel1) mit NullLayout eingebunden. Jetzt geschieht etwas in dem Programm und dann soll der Button dort gelöscht werden (panel1.remove()) und in ein anderes JPanel (panel2) mit FlowLayout eingebunden werden (panel2.add()). Komischerweise wird der Button in panel2 an genau den gleichen Koordinaten eingebunden wie beim NullLayout und das FlowLayout wird irgendwie nicht benutzt. Woran kann das liegen? Wenn ich nach dem adden revalidate() oder doLayout() ausführe verschwindet der Button einfach ganz.

Danke schon mal!


----------



## SE (26. August 2011)

Das liegt daran das du für das NullLayout die Methode JComponent.setBounds() aufgerufen hast. Du musst erst die Bounds löschen bevor das FlowLayout greifen kann.


----------



## TobyNick (26. August 2011)

Ok stimmt, ich habe den Button mit setSize() und setLocation() verändert. Aber wie lösche ich die Bounds jetzt zurück? setBounds(0,0,0,0) funktioniert nicht.


----------



## SE (27. August 2011)

1) Doppel-Posts , im Sinne von : gleicher Inhalt , sind hier unerwünscht.
2) Warum machst du es dir so umständlich und fügst erst eine Component auf ein NullLayout hinzu wo du auf setBounds() angewiesen bist und willst diese dann später auf ein Panel verschieben welches ein LayoutManager besitzt und dir da die Bounds in die Query kommen. Einfacher wäre es doch wenn du das ganze entweder komplett auf einem Panel machen würdest *hier natürlich vorzugsweise das mit dem LayoutManager* oder du nimmst eine zweite Component.

Wie man über setBounds() gemachte absolute Positions- und Größenangaben wieder "löscht" weis ich nicht ... ich bin nur davon ausgegangen das es möglich sein müsste.


----------



## TobyNick (27. August 2011)

Nun ja. Ich habe in dem Programm Würfel als Buttons (damit man sie anklicken kann) auf dem ersten Panel zufällig angeordnet. Jetzt kann man Würfel auswählen. Wenn man sie auswählt, sollen sie in dem einen Panel gelöscht werden und in ein anderes Panel eingefügt werden, allerdings sollen die in dem Panel geordnet sein.
So als ob die Würfel in so einem Bereich gewürfelt worden sind (durcheinander / zufällige Anordnung) und man sich dann die Würfel rauspickt und sie vor sich legt, aber das macht man ja ordentlich / in einer Reihe...deswegen FlowLayout.


----------



## Fabio Hellmann (27. August 2011)

Hi,
warum machst du es dann nicht so, da ein Würfel ein Objekt ist, dass du dieses Objekt einfach von dem einen Panel löst und in ein anderes setzt? Diese Würfel-Objekte werden dann (wie du es auch schon gemacht hast) über ein JPanel angezeigt. Und wenn du auf einen Würfel geklickt hast, dann wird das JPanel von dem Würfel-Objekt gelöscht und du zeigst das Würfel-Objekt auf der anderen Seite in einem neuen JPanel an.

Gruß

Fabio


----------



## TobyNick (27. August 2011)

Ich weiß nicht ob ich dich richtig verstehe, aber so mache ich das doch eigentlich. Ich lösche den Würfel von dem einen Panel mit NullLayout: panel1.remove(wuerfel); und füge es ins andere Panel mit FlowLayout ein: panel2.add(wuerfel);
Oder wie meinst du das? Entschuldige, falls ich dich falsch verstanden habe.


----------



## SE (27. August 2011)

Normalerweise sollte wenn du eine Component in einen Container mit LayoutManager addest von diesem die setBounds() Methode aufgerufen werden welche die von dir vorher gemacht Bounds überschreibt. Ich habe es zwar noch nicht getestet ... aber laut dem OOP-Konzept von Java und den Zusammenhängen in GUI-Strukturen sollte es eigentlich so sein. Aus irgend einem Grund wird jetzt aber genau das bei dir nicht getan.
Es wäre interessant zu sehen WIE du den "Würfel" von Panel1 auf Panel2 überträgst *bitte den kompletten relevanten Code*. Vielleicht findet man darin ja einen Fehler. So ohne Source fällt mir jetzt auch keine Lösung mehr ein.


----------



## TobyNick (28. August 2011)

Ok dann poste ich mal den Code ;-)


```
//Im ActionListener der Würfel-Buttons

//...

public void actionPerformed(ActionEvent e) {
		Wuerfel ausgewaehlt = (Wuerfel) e.getSource();
		
		panel1.entferneWuerfel(ausgewaehlt); //panel1 ist ein Objekt einer Klasse die von JPanel erbt, dass heißt es ist auch direkt das Panel, aus dem entfernt werden soll
		player.addWuerfel(ausgewaehlt); // player ist Spieler-Objekt
	}


//Die Klasse von panel1, wo die Wuerfel anfangs drin sind (mit NullLayout)

public class Wuerfelpott extends JPanel {

ArrayList<Wuerfel> wuerfel;

//...

public void entferneWuerfel(Wuerfel w) {
		wuerfel.remove(w);
		this.remove(w);
		this.repaint();
	}

}

public class Spieler {

ArrayList<Wuerfel> wuerfel;
Ablage ablage; // Ablage erbt von JPanel und hat das FlowLayout, ablage ist halt das 2. Panel

public void addWuerfel(Wuerfel w) {
		wuerfel.add(w);		
		ablage.add(w);
	}
}
```

Also alles nichts besonderes


----------



## SE (28. August 2011)

Ja ... nicht besonderst gut vor allem. Mir fallen da selbst in diesem Stück Code einige Fehler auf.

1) Nach dem der Würfel vom Würfelpott entfernt wurde reicht ein einfaches

```
this.repaint();
```
nicht. Ersetze es mal durch

```
this.validate();
this.update(this.getGraphics());
```

2) Analog gilt es natürlich auch für das Hinzufügen einer Component in ein Layout. Wenn du ein Layout veränderst MUSS IMMER validate() aufgerufen werden. also müsste die ganze Methode so aussehen

```
public void addWuerfel(Wuerfel w)
{
	wuefel.add(w);
	ablage.add(w);
	ablage.validate();
	ablage.update(ablage.getGraphics());
}
```

Ich hoffe das hilft dir bei deinem Problem.

Der Grund : Component.setBounds() wird erst durch das validate() aufgerufen , aber ein simples add() reicht nicht.


----------



## Fabio Hellmann (28. August 2011)

Hi TobyNick,
nein, du hast mich damals ein wenig falsch verstanden. Ich habe dir hier mal einen kleinen Beispiel-Code geschrieben, um dir das mal ein bischen besser veranschaulichen zu können.

Die Klasse *Pott* fügst du zu deinem JFrame hinzu. Das Pott-Objekt übernimmt die Anzeige der einzelnen Würfel. D.h. der aktuelle Spieler wird über die Methode setActualPlayer(Player) gesetzt und danach wird die Methode update() aufgerufen. Die Methode update() wird immer dann aufgerufen, wenn der Spieler z.B. neu gewürfelt hat oder bei sonstigen Änderungen.

```
public class Pott extends JPanel
	{
		private Player player;
		private final List<JPanel> pottPanels;
		
		/**
		 * 
		 */
		public Pott() {
			this.pottPanels = new LinkedList<JPanel>();
			
			// Je nachdem, wieviele JPanels du zum Würfelzeichnen brauchst
			// ...
			JPanel panel1 = new JPanel();
			pottPanels.add(panel1);
			add(panel1);
			JPanel panel2 = new JPanel();
			pottPanels.add(panel2);
			add(panel2);
			JPanel panel3 = new JPanel();
			pottPanels.add(panel3);
			add(panel3);
			JPanel panel4 = new JPanel();
			pottPanels.add(panel4);
			add(panel4);
			JPanel panel5 = new JPanel();
			pottPanels.add(panel5);
			add(panel5);
			// Den Panels müsstest du auch noch einen MouseListener für ein Click-Event mit übergeben.
			// Oder du nimmst statt JPanel's einfach JButton's.
		}
		
		public void setActualPlayer(Player player) {
			this.player = player;
		}
		
		public void update() {
			List<Cube> notSelectedCubes = player.getNotSelectedCubes();
			
			for (int i = 0; i < pottPanels.size(); i++) {
				JPanel panel = pottPanels.get(i);
				
				if(i < notSelectedCubes.size()) {
					Cube cube = notSelectedCubes.get(i);
					cube.draw((Graphics2D) panel.getGraphics());
				} else {
					panel.validate();
					panel.update(panel.getGraphics());
				}
			}
		}
	}
```

Die Klasse *Player* enthält jetzt unsere Würfelobjekte. Da nur der Spieler (nach OOP) weiß welche Würfel er "selektiert" hat und welche nicht, werden diese beiden Methoden - getNotSelectedCubes() und getSelectedCubes() - dem Player-Objekt hinzugefügt. Zudem bekommt das Player-Objekt noch die Methode dice() zum würfeln. Wird diese Methode aufgerufen, werden alle Würfel (welche nicht selektiert sind) gewürfelt.

```
public class Player
	{
		private final List<Cube> cubes;
		
		public Player() {
			this.cubes = new ArrayList<Cube>();
			cubes.add(new Cube());
			cubes.add(new Cube());
			cubes.add(new Cube());
			cubes.add(new Cube());
			cubes.add(new Cube());
			// Je nachdem, wieviele Würfel du haben willst
			// ...
		}
		
		public void dice() {
			for (int i = 0; i < cubes.size(); i++) {
				Cube cube = cubes.get(i);
				if(!cube.isSelected()) {
					cube.dice();
				}
			}
		}
		
		public List<Cube> getNotSelectedCubes() {
			List<Cube> selectedCubes = new ArrayList<Cube>();
			for (int i = 0; i < cubes.size(); i++) {
				Cube cube = cubes.get(i);
				if(!cube.isSelected()) {
					selectedCubes.add(cube);
				}
			}
			return selectedCubes;
		}
		
		public List<Cube> getSelectedCubes() {
			List<Cube> selectedCubes = new ArrayList<Cube>();
			for (int i = 0; i < cubes.size(); i++) {
				Cube cube = cubes.get(i);
				if(cube.isSelected()) {
					selectedCubes.add(cube);
				}
			}
			return selectedCubes;
		}
	}
```

Die Klasse *Cube* ist nun also unser Würfel-Objekt. Von diesem Objekt können wir nun erfragen, ob es selektiert wurde und welche Nummer es gerade zeigt. Zudem (fürs zeichnen) können wir noch die x-/y-Koordinaten einsehen und ändern.

```
public class Cube
	{
		private int shownValue;
		private boolean selected;
		private int x = 0;
		private int y = 0;
		
		public void dice() {
			this.shownValue = (int) (Math.random()*6+1);
		}
		
		public int getShownValue() {
			return shownValue;
		}
		
		public void setSelected(boolean isSelected) {
			this.selected = isSelected;
		}
		
		public boolean isSelected() {
			return selected;
		}

		public void setX(int x) {
			this.x = x;
		}

		public int getX() {
			return x;
		}

		public void setY(int y) {
			this.y = y;
		}

		public int getY() {
			return y;
		}
		
		public void draw(Graphics2D g) {
			g.drawRect(x, y, 40, 40);
			g.drawString(String.valueOf(shownValue), x+19, y+18); // Oder durch selber gezeichnete Punkte ersezten
		}
	}
```

Ich hoffe ich konnte dir meinen Gedankengang ein wenig veranschaulichen mit diesen Codeausschnitten. Bitte bedenke, dass ich diesen Code vorher nicht ausprobiert habe und ich daher nicht garantieren kann, dass er zu 100% einsatzbereit/lauffähig (sprich: Fehler können vorhanden sein) ist.
Du wirst wahrscheinlich nichts desto drotz die ein oder anderen Änderungen vornehmen müssen. Diese Arbeit wird dir wohl nicht erspart bleiben. 

Falls du noch Fragen haben solltest, nur zu. 

Gruß

Fabio


----------



## TobyNick (29. August 2011)

@Spikee: Danke erstmal. Ich wusste nicht, dass repaint() nicht ausreicht. aber wofür gibt es dann repaint()? auf jeden fall, wenn ich validate benutzte oder auch revalidate, dann werden die würfel gar nicht mehr angezeigt. nicht mal mehr an den falschen koordinaten. einfach weg.
ich verstehe es einfach nicht. hmm...ich kann verstehen wenn ihr das thema schon satt habt ;-)


----------



## TobyNick (29. August 2011)

@Fabio: Danke für die Mühe, aber ich verstehe noch nicht, wie mir das bei meinem Problem helfen soll. Es geht hier ums NullLayout und FlowLayout und darum, wie die Komponenten angezeigt werden, wenn sie von einem Panel mit dem einen Layout in ein anderes Panel mit dem anderen Layout verschoben werden.
Du hast dir sehr viel Mühe gemacht um zu zeigen, wie man die Würfel verwaltet, aber das ist kein Problem. Das habe ich alles und das funktioniert.


----------



## Fabio Hellmann (29. August 2011)

Ich wollte dir damit nur zeigen, dass du die Würfel auch von den JPanel's trennen kannst. Dadurch würdest du dir das verschieben von Komponenten durch die verschiedenen Layouts sparen.


----------

