AWT/Swing: Wie funktioniert das GridBagLayout?

Hallo, ich möchte das GridBagLayout einführen, weil ich dann, denke ich, mit weniger JPanel auskomme… Es soll genau so aussehen wie bei dem folgendem Code und das Resize behaviour soll auch gleich sein:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.WindowConstants;

public class GridBagLayoutTest {
	public static class MyBar {
		JProgressBar bar = new JProgressBar();
		JLabel text = new JLabel("irgendwas", JLabel.CENTER);
		JPanel panel = new JPanel(new BorderLayout());

		public MyBar() {
			panel.add(bar, BorderLayout.CENTER);
			panel.add(text, BorderLayout.EAST);
			text.setPreferredSize(new Dimension(175, text.getPreferredSize().height));
		}
	}

	private JFrame frame = new JFrame("Version 1");
	private JPanel panel1 = new JPanel();
	private List<MyBar> bars = new ArrayList<>();

	public GridBagLayoutTest() {
		for (int i = 0; i < 4; i++) {
			bars.add(new MyBar());
		}

		frame.setLayout(new BorderLayout());
		panel1.setLayout(new GridLayout(bars.size(), 1));
		for (MyBar myBar : bars) {
			panel1.add(myBar.panel);
		}
		frame.add(panel1, BorderLayout.NORTH);
		frame.setSize(800, 600);
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}

	public static void main(String[] args) {
		new GridBagLayoutTest();
	}
}

Hätte dafür jemand einen Ansatz? Ich kapiere das GridBagLayout nicht: https://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html

Ich bedanke mich vielmals im Voraus

Das GridBagLayout hat ein paar versteckte Problemchen, ich hantiere inzwischen lieber mit verschachtelten BorderLayouts und GridLayouts. Wenn man jeden Panel in seiner eigenen Methode erstellt und diese ordentlich benennt, bleibt das meiner Erfahrung nach auch übersichtlich und gut wartbar.

2 Likes

Das GridBagLayout ohne grafische Unterstützung zu verwenden ist nahe an Masochismus. Es gibt soviele gute Alternativen wie FormLayout, TableLayout…

1 Like

Ok, ich hatte früher mal einen Prof, der wollte in einer Prüfung, dass das GridBagLayout eingesetzt wird. Dabei ging es um Swing und eine UI. Ich hab dann eine identisch aussehende UI auch mit dem BorderLayout und JPanel gebastelt, und für diese Teilaufgabe 0 Punkte bekommen. Damals war mit aber noch nicht bewusst, dass das GridBagLayout „unsinnig“ ist… Ich hätte mich beschweren können, tat ich aber nicht. :confused: Danke für eure Antworten. :slight_smile: Edit: Hatte die Prüfung trotzdem bestanden.

Gut, dann hat sich das ja erledigt. Ich hatte schon befürchtet, dass einer der alten Swinger :older_man: sich hier jetzt Mühe gibt, nur um von dir dann Beschwerden zu hören, dass irgendein Pixel am Ende doch die falsche Farbe hat.

Aber kurz: Es gibt eine Sache, die (wie ich finde) nicht gut mit den eingebauten Layouts nachbildbar ist (und nur dafür eine neue dependency reinziehen ist auch blöd), nämlich ein einfaches n-spaltiges Layout mit unterschiedlich breiten Spalten:

[Some Button               ] [ Some text Field                    ] [Checkbox]
[Some Button with long text] [ Another Text Field                 ] [Checkbox]
[Short                     ] [ Yet Another Text Field             ] [Checkbox]

Deswegen hatte ich mir nur für diesen Zweck mal eine GridBagLayouts-Klasse erstellt, mit der man sowas recht leicht zusammenbasteln kann (und die intern ein einfaches (!) GridBagLayout verwendet).

Ja, ziemlich trivial, aber … das sind kleine Codeschnipsel halt immer. In der Lib ist auch noch ein bißchen nicht ganz so triviales Zeug drin…

1 Like

Ehhh, dumme Frage, aber wie binde ich das denn ein? Und wäre es lizenztechnisch erlaubt, dass ich Teile deiner GridBagLayouts Klasse einfach kopiere, oder ist dann Polen offen?

Wie’s auch sei, vielen Dank für deine Antwort. :slight_smile:

Lesen wäre von Vorteil

Ja, vielleicht kannst du es mir ja erklären, anstatt einen dummen Kommentar abzugeben. :slight_smile:

In JEDER meiner -java-Dateien auf GitHub ist der MIT-Header. Aber hiermit erkläre ich die GridBagLayouts-Klasse offiziell als „Public Domain“, oder alternativ, veröffentliche sie hier nochmal unter der WTFPL. (Aber nur diese GridBagLayouts-Klasse. Bei anderen Klassen steckt einiges an Arbeit drin…)

Das meinte ich doch. Es soll nicht unhöflich klingen, aber ich brauche zurzeit eh nur diese eine Klasse (bzw. TEILE der Klasse :wink: ), und b) ich hätte ohnehin nicht die komplette Library kopiert… Danke!

Im Wiki gibts mehrere Artikel über das GridBagLayout.
In Deutsch: https://wiki.byte-welt.net/wiki/GridBagLayout

Ich habe früher viel mit GridBagLayout gebaut. So schwer und unverständlich ist es dann doch nicht. Tricky zum Teil aber schon.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.WindowConstants;

public class GridBagLayoutTest {
	public static class MyBar {
		JProgressBar bar = new JProgressBar();
		JLabel text = new JLabel("irgendwas", JLabel.CENTER);
		JPanel panel = new JPanel(new BorderLayout());

		public MyBar() {
			panel.add(bar, BorderLayout.CENTER);
			panel.add(text, BorderLayout.EAST);
			text.setPreferredSize(new Dimension(175, text.getPreferredSize().height));
		}
	}

	private JFrame frame = new JFrame("Version 1");
	private JPanel panel1 = new JPanel();
	private List<MyBar> bars = new ArrayList<>();

	public GridBagLayoutTest() {
		for (int i = 0; i < 4; i++) {
			bars.add(new MyBar());
		}

		//frame.setLayout(new BorderLayout()); //hat er doch von Hause aus
		panel1.setLayout(new GridLayout(bars.size(), 1));
		for (MyBar myBar : bars) {
			panel1.add(myBar.panel);
		}
		frame.add(panel1, BorderLayout.NORTH);
		frame.setSize(800, 600);
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}

	public GridBagLayoutTest(String title) {
		
		panel1.setLayout(new GridBagLayout()); //Layout für Panel festlegen
		GridBagConstraints gbc = new GridBagConstraints(); //Layout-Einstellungen erzeugen

		gbc.gridx = 0; //Zähler der Zellen in X-Achse initialisieren
		gbc.gridy = 0; //Zähler der Zellen in Y-Achse initialisieren
		gbc.anchor = GridBagConstraints.NORTHWEST; //Ausrichtung der folgenden Zellen nach Nordwest
		gbc.fill = GridBagConstraints.HORIZONTAL; //horizontale Ausdehnung der folgenden Zellen ermöglichen
		gbc.weightx = 1.0; //Gewichtung der X-Achse der folgenden Zellen gbc.anchor und gbc.fill werden hier wirksam

		for(int i = 0; i < 4; i++) {
			panel1.add(new JProgressBar(), gbc);
			gbc.gridy++;
		}

		gbc.gridx++;
		gbc.gridy = 0;
		gbc.weightx = 0.0; //Gewichtung in X-Achse für folgende Zellen aufheben
		
		for(int i = 0; i < 3; i++) {
			panel1.add(createLabel(), gbc);
			gbc.gridy++;
		}

		gbc.weighty = 1.0; //Gewichtung der Y-Achse der letzten Zelle, gbc.anchor werden hier wirksam. Dadurch werden alle Zellen nach oben gedrückt.
		panel1.add(createLabel(), gbc);	
		
		frame.setTitle(title);
		frame.add(panel1);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(800, 600);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}

	private JLabel createLabel() {
		JLabel label = new JLabel("irgendwas", JLabel.CENTER);
		label.setPreferredSize(new Dimension(175, label.getPreferredSize().height));
		return label;
	}

	public static void main(String[] args) {
		new GridBagLayoutTest("GridBagLayout");
	}
}

Dein Code etwas ergänzt. Durch Änderung des Konstruktor-Aufrufs kannst du die verwendeten LayoutManager ändern.

Wenn ich sowas sehe bin ich wirklich dankbar für den SceneBuilder


Ich weiss ich weiss die Frage hier ist über Swing, aber in JavaFX ist das mit dem GridPane in 15 Sekunden gemacht und ich verkneif mir den Kommentar jetzt schon seit ein paar Tagen.

@L-ectron-X
Das ist wirklich außerordentlich gut geschrieben, wenn du mir das Kompliment erlaubst :+1:

1 Like

Schluss jetzt mit den Höflichkeiten. :sweat_smile: @L-ectron-X Danke für den Code.

Ich bin immer wieder erstaunt, wenn Leute Sekunden mit Minuten oder Stunden verwechseln…

Du hast recht, ich hab übertrieben.

Es sind 30 Sekunden :lying_face:

Youtube!

rosycheeks-mochi-peach