JLabel.setText() zerstört das Layout

Hallöle,

ich habe da ein etwas größeres Problemchen.

Mein Projekt sieht folgendermaßen aus (siehe Bild):

In der Mitte das Blaue ist ein Element meines GridLayoutes.
Das GridLayout selbst sieht so aus:

        spielframe.setPreferredSize(new Dimension(1400,800));
        spielframe.setMinimumSize(new Dimension(1050,600));
        spielframe.setResizable(true);
        spielframe.setIconImage(Toolkit.getDefaultToolkit().getImage(new URL(BaseURL.getJarBase(Spielfeld.class), "./favicon.png")));
        
        Container contentPane = spielframe.getContentPane();
        contentPane.setLayout(new GridBagLayout());

        spielframe.add(new Barkartenecke(), new GridBagFelder(0, 0, 1, 1, 0.15, 0.5));
        spielframe.add(new Uebersichtsecke(), new GridBagFelder(0, 1, 1, 1, 0.15, 0.5));
        spielframe.add(new Spielfeld(), new GridBagFelder(1, 0, 1, 2, 0.67, 1.0)); //Das hier ist das angesprochene Feld
        spielframe.add(new Spielkartenecke(), new GridBagFelder(2, 0, 1, 1, 0.18, 0.6));
        spielframe.add(new Bildecke(), new GridBagFelder(2, 1, 1, 1, 0.18, 0.4));
        
        spielframe.pack();
        spielframe.setLocationRelativeTo(null);```

Das Element `spielfeld` ist das angesprochene.

Der Inhalt dieses Spielfeldes ist folgender:
```package spiel;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

public class Spielfeld extends JPanel {

	private Spielzelle spielfeldzelle[][] = new Spielzelle[11][11];
	private static JLabel meldungsbox = new JLabel();
	private static ArrayList<Spielzelle> spielfeldtisch = new ArrayList<Spielzelle>(12);
	private static ArrayList<Spielzelle> spielfeldstuhl = new ArrayList<Spielzelle>(24);
	private int aktstuhlnummer;

	protected Spielfeld() {
		setLayout(new GridBagLayout());
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.weightx = 1.0;
		gbc.weighty = 1.0;
		gbc.fill = GridBagConstraints.BOTH;
		
		for(int y=0;y<11;y++) {
			for(int x=0;x<11;x++) {
				gbc.gridx = x;
				gbc.gridy = y;

				if(y<10) {
					spielfeldzelle[x][y] = new Spielzelle(Spielzelle.Typ.Leer);
					spielfeldzelle[x][y].setBackground(new Color(0,255,255));
					spielfeldzelle[x][y].setOpaque(true);
					add(spielfeldzelle[x][y], gbc);
				} else if(y==10) {
					gbc.gridwidth = 11;
					meldungsbox.setBackground(new Color(0,255,255));
					meldungsbox.setOpaque(true);
					meldungsbox.setHorizontalAlignment(SwingConstants.CENTER);
					add(meldungsbox, gbc);
					break;
				}
			}
		}
		feldmalen();
	}

	private void feldmalen() { 
		int[] tischkoordx = {4,5,6,7,8,7,6,5,4,3,2,3};
		int[] tischkoordy = {3,2,3,4,5,6,7,8,7,6,5,4};
		for(int i=0;i<12;i++) {
			spielfeldtisch.add(spielfeldzelle[tischkoordx**][tischkoordy**]);
			spielfeldzelle[tischkoordx**][tischkoordy**].setTyp(Spielzelle.Typ.Tisch);
		}
		
		int[] stuhlkoordx = {4,5,6,7,8,7,6,5,4,3,2,3,4,5,6,9,8,7,6,5,4,3,2,1};
		int[] stuhlkoordy = {4,1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,7,8,9,8,7,6,5};
		for(int i=0;i<24;i++) {
			final int j = i;
			spielfeldstuhl.add(spielfeldzelle[stuhlkoordx**][stuhlkoordy**]);
			spielfeldzelle[stuhlkoordx**][stuhlkoordy**].setTyp(Spielzelle.Typ.Stuhl);
			spielfeldzelle[stuhlkoordx**][stuhlkoordy**].addMouseListener(new MouseAdapter() {
            	@Override
				public void mouseClicked(MouseEvent e) {
            		if(Spielkartenecke.getAkthandkartnum()!=-1) {
            			new Spielzuege().legegastkarte(Spielkartenecke.getAkthandkartnum(),j);
            		}
            	}
            });
		}
	}
	
	protected static ArrayList<Spielzelle> getSpielfeldtisch() {
		return spielfeldtisch;
	}

	protected static void setSpielfeldtisch(ArrayList<Spielzelle> spielfeldtisch) {
		Spielfeld.spielfeldtisch = spielfeldtisch;
	}

	protected static ArrayList<Spielzelle> getSpielfeldstuhl() {
		return spielfeldstuhl;
	}

	protected static void setSpielfeldstuhl(ArrayList<Spielzelle> spielfeldstuhl) {
		Spielfeld.spielfeldstuhl = spielfeldstuhl;
	}
	
	protected int getAktstuhlnummer() {
		return aktstuhlnummer;
	}

	protected void setAktstuhlnummer(int aktstuhlnummer) {
		this.aktstuhlnummer = aktstuhlnummer;
	}
	
	protected static JLabel getMeldungsbox() {
		return meldungsbox;
	}
}```

Also zuerst mache ich da ein 11 mal 10 Feld rein und danach auf die gesamte untere Zeile ein JLabel zur Anzeige.
Also sozusagen wie ein 11 mal 11 Feld, wo das unten verschmolzen ist.

Und hier liegt nun das Problem.
Wie ihr seht, ist in der Meldungsbox massig Platz. Man schaue nur dieses poplige "Startzeit: xxxx" an. (gibt an, wie lange mein Programm in Millisekunden lädt). Da ist Unmengen Platz zur Anzeige.

Aber Java macht etwas, was ich überhaupt nicht verstehe.

Wenn ich den Text in der Box verändere, verschiebt sich das gesamte Layout.
```.getMeldungsbox().setText("Die Nationalität dieses Gastes stimmt nicht mit der Tischnationalität überein.")```
Dann sieht es so aus:


Das JLabel krallt sich also immer mehr Platz, obwohl es eigentlich genug hatte, um den Text anzuzeigen.

Ich möchte gerne, dass das JLabel genau so groß bleibt, wie es jetzt ist und rein gar nichts das negativ beeinflussen kann.

Ich komme da nicht weiter. Ich hoffe ich habe mein Problem logisch verständlich erläutern können.

Danke im Voraus für eure Hilfe.

Gruß
Lukas
=====
PS: Mein gesamtes Projekt sieht man hier:
https://github.com/Dabendorf/Caf-International-Grafik-/tree/master/src/spiel
Falls sich jemand damit beschäftigt und den Fehler möglicherweise woanders auffindet.

PS#2: Das Layout ist Resizable. D. h. beim verändern der Größe durch den Nutzer muss das JLabel weiterhin auch seine Proportion im Vergleich zum Rest behalten. Was es bisher auch tut. Nur als kleine Anmerkung, falls jemand etwas gefunden hat.

kein Testprogramm mit knappen Nachbauen der Situation?

setze mal
meldungsbox.setPreferredSize(new Dimension(0, 20));
dazu, aber erkennbar maximal als Hack anzusehen

wobei ein Hack beim GridBagLayout durchaus oft das bestmögliche Verfügbare sein kann…

Du hast eine Gewichtung auf die Breite des JLabels gesetzt. Das heißt, dass es bei der Dimensionierung vorrangig behandelt wird und ihm so bei Veränderung der Breite des Inhaltes, mehr Platz verschafft wird.
Daher solltest du zuerst probieren, ob es hilft, die Gewichtung gbc.weightx für meldungsbox auszukommentieren.

Ansonsten könnte es helfen, nach der Initialisierung der GUI die maximale Größe vom meldungsbox zu limitieren.
meldungsbox.setMaximumSize(spielfeld.getPreferredSize()));

Hallöle und vielen dank euch beiden für eure Antworten,

@L-ectron-X
Das mit weightx führt leider zu keinem Erfolg.
Das Argument ist wie man erkennen kann generell eingefügt.

Das hier:

		gbc.weighty = 1.0;
		gbc.fill = GridBagConstraints.BOTH;```
Ist ja alles samt ganz vorne bestimmt und wird nicht mehr verändert, ergo muss es ja für alle Elemente gelten.
Wenn ich es auskommentiere, artet es so aus:


Alternativ habe ich es auch mal versucht es explizit nur in die If-Bedingung der anderen Felder zu packen und ähnliches. Das führte leider in keiner Aufführung zum Erfolg. Entweder hat es nichts geändert, oder wie im Beispiel oben alles "vernichtet".
Oder Du meinst was anderes. Wenn ja, dann weiße mich bitte darauf hin. ;)

Zu der anderen Idee:
Ich habe in der Tat schon darüber nachgedacht, dass ich es mit PreferredSize machen könnte. Aber ich bin immer wieder darüber gestolpert, dass ich etwas nicht nachvollziehen kann.  Ich lege nur PreferredSize einmal global für das Gesamtfenster fest und lege dann die Relationen der einzelnen Unterobjekte fest. Deshalb kann ich es nicht ganz nachvollziehen, welchen Sinn es Javatechnisch hat dann Einzelobjekten absolute Werte zu geben, wenn ich das Layout doch verändern kann.

Ich habe es mal mit SlaterBs Variante versucht und Tatsache, es funktioniert! Er verschiebt nichts mehr!

Aber ich würde es wie gerade geschrieben sehr schön finden, wenn mir nochmal einer erklären könnte wieso das jetzt so ist, wie es ist.
```meldungsbox.setPreferredSize(new Dimension(0, 20));```

Viele Grüße und Danke schön.
LUkas

frag mal die PreferredSize deiner 10 Elemente ab bzw. des mittleren Panel und was links und rechts herauskommt,
falls das nur ein Hunger-Rennen von links 100, in der Mitte 200, rechts 100 ist,
dann könnte ein langer Text mit PreferredWidth 300, auf das mittlere Panel übertragen, ja durchaus was bewirken

auch wenn du eigentlich auch noch für die 3 HauptPanel Gewichte gesetzt hast (eigene Frage was da wieviel bewirkt)

ob du den langen Text am Anfang oder erst später setzt, gleiche Auswirkung, das ist konsistent,

mal abgesehen davon dass man vielleicht keine Änderungen haben will, aber gibt keinen Ausschalter,
wäre ja auch schwer fürs Layout, sich sämtliche Verhältnisse separat zu merken und auf Größenänderungen des Fensters muss es ja spätestens reagieren,
und dann auch ganz nett, enge Komponenten stärker zu erweitern als die die eh zufrieden sind

wie auch immer das Layout auf breites Label reagiert (auch bereits am Anfang),
die Wirkung des setPreferredSize-Aufrufs dürfte dabei klar sein, keine Änderungen mehr,
Label hat nix in der Verschiebung der drei HauptPanel zu sagen, geht nur noch nach dem Gitter für Mitte + Rest,
dass es fürs Label keine negativen Auswirkungen hat ist mit dem FILL über volle Breite klar

Ich hätte bei dieser Aufteilung das JLabel gar nicht über das GridBagLayout mit eingebunden sondern lieber in ein weiteres BorderLayout verschachtelt. Dann halt die “Spielfläche” im Center und das JLabel halt als extra im South.
Da muss ich mal nachfragen : wie bist du auf diese Idee gekommen ?

Hallöle,

meine Kenntnisse zur Grafikprogrammierung sind erst sehr kurzweilig, existieren also noch nicht lange.
Die ganzen Innereien des Projektes krieg ich inzwischen mit meinen Javakenntnissen gut hin. Aber meine Fähigkeiten sind so ein wenig DOSmäßig, das heißt in der Konsole wird alles eingelesen und ausgegeben. Sowie ich es graphisch darstellen möchte kommen da Probleme. :slight_smile:

Habe mich jetzt eine ganze Weile damit befasst und habe lange gebraucht um kompetent mit GridBagLayout umzugehen.
Die fassung wie sie jetzt ist, stammt aus dem Januar, das Projekt ist seitdem weit vorangekommen, nur die Grafik stagniert. Da komm ich ab und an in Probleme.
Aber aktuell find ich es für meine Verhätnisse richtig gut.

Die Idee das nochmal zu unterteilen find ich sehr gut!
Also würdest Du das in ein BorderLayout verpacken, wo das JLabel unten South ist und oben das GridLayout 11 mal 10 North ist?

Schau ich mir mal an. Läuft zwar gerade, aber für Codeverbesserungen probiert man das immer gern aus.
Gruß
Lukas

Merk dir vor dem fraglichen Element den Wert von weightx, setzte weightx neu, und hinterher setze weightx auf den alten Wert zurück.