Button als einziges Element mittig zentrieren

Guten Tag,

ich baue eine graphische Oberfläche mit GridBagLayout zusammen. Das läuft wunderbar.

Ich habe nur ein Problem. In der Mitte dieses Gridbaglayouts verläuft senkrecht ein großes JPabel. Dieses JPanel hat nur ein einziges Element, einen großen Neustartbutton. Wenn ich diesen hinzufüge nimmt der logischerweise die gesamte riesige Fläche ein, wie im Bild zu sehen.

Ich würde es schön finden, wenn man den einfach vertikal in der Mitte aufhängen könnte. Einfach vertikal zentriert und horizontal darf er ruhig so breit bleiben.
Das hier ist mein Quellcode:

	
	private JButton neustart = new JButton("Neustart");
	
	public Mittelflaeche() {
		this.setLayout(new BorderLayout());
		this.add(neustart,BorderLayout.CENTER);
		neustart.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				Quartett.neuepartie(true);
			}
		});
	}

}```

Ich habe es mit BorderLayout versucht, aktuell im Beispiel. Falls ihr euch wundert, das ergibt aktuell natürlich keinen Sinn, weil ich nur ein Element hatte. Ich hatte versucht als kleinen Trick oben und unten ein leeres JPanel/JLabel anzuzeigen, aber wenn es leer ist, kriegt es leider auch keinen Platz zugesprochen.

Kann mir jemand von euch verraten, wie ich mein Ziel sinnvoll erreichen kann? Früher hab ich bei NullLayout einfach absolute Werte genommen, das geht hier natürlich nicht mehr. ;)
Ich bin offen für alle für mich verständlichen Ideen. :)


Schöne Grüße
Lukas

wiederum ein GridBagLayout ginge

            GridBagConstraints c = new GridBagConstraints();
            c.fill = GridBagConstraints.HORIZONTAL;
            c.weightx = 1;
            add(neustart, c);

this. bei Methodenaufrufen finde ich übrigens störend,

ohne Variable, an der aufgerufen wird, kann es fast nur das eigene Objekt sein,
Klassenname bei static evtl. noch,

this lieber exklusiv für Unterscheidung lokale Variablen vs. Instanzattribute nutzen, weniger ist mehr
(interessant sogar, sehe ich nun noch, dass du gar nicht this.neustart schreibst, ich kopiert dann auch nicht)

Hallo und vielen Dank für Deine Antwort,
dass ich darauf nicht gekommen bin. Ich war so stur darauf das irgendwie mit Box oder Borderlayout hinzukriegen, weil ich dachte mit GridBag geht das nicht. Aber das ist logisch und verständlich. Klappt gut. Vielen Dank! :slight_smile:

Zum this: Ist irgendwie angelernt. Mein Informatiklehrer hat das immer so gemacht, hab ich irgendwie übernommen. Finde irgendwie einfach setLayout(); sieht so „nackig“ aus. Mit this kennzeichne ich ihr, dass ich nicht vergessen habe das Element davor zu schreiben sondern explizit die gesamte Klasse meine.
Aber ja, auch hier sehe ich, der eigentlich this-Nutzungszweck ist ein anderer. Vielleicht änder ich ja das. :smiley: Bisher kam ich so mit klar.

Viele Grüße euch
Lukas

[OT][quote=FranzFerdinand]gesamte Klasse[/quote]nein nicht die klasse, sondern die “aktuelle instanz”…[/OT]

Hallöle,

eine Frage muss ich nochmal stellen.
Ich dachte eigentlich mit dem GridBagLayout gut klarzukommen, aber anscheinend muss ich da noch einige Kniffe lernen.
Folgendes. Ich habe vor ewiger Zeit mal ein Projekt gemacht wo links eine Ampel angezeigt wird und rechts drei Buttons sind.
Das hab ich mit dem bösen NullLayout gemacht und es sieht so aus:

Nun wollte ich das mit GridBagLayout bauen, unter anderem auch, damit ich die Fenstergröße anpassen kann.
Nach langem basteln ist das beste, was ich erreichen konnte das hier:

Der Quelltext wo das generiert wird sieht so aus:

	
	private JFrame frame1 = new JFrame("Ampelschaltung");
	private Canvas canvas = new Canvas() {
		public void paint(Graphics stift) {
			zeichne(stift);
		}
	};
	private Button buttonautomatik = new Button();
	private Button buttonwarnung = new Button();
	private Button buttonweiter = new Button();
	private int ampelstatus = 0;
	private int warnstatus = 0;
	private int modus = 0; //0=Nichts; 1=Normalschaltung, 2=Warnmodus
	private Thread thread = null;
	
	public Ampel() {
		frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame1.setPreferredSize(new Dimension(400,400));
		frame1.setMinimumSize(new Dimension(400,400)); //ANPASSEN
		frame1.setResizable(true);
		Container cp = frame1.getContentPane();
		cp.setLayout(new GridBagLayout());
		
		buttonautomatik.setLabel("Automatik ein");
		buttonautomatik.setVisible(true);
		buttonautomatik.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				buttonAutomatik_ActionPerformed();
			}
		});
		buttonwarnung.setLabel("Warnmodus ein");
		buttonwarnung.setVisible(true);
		buttonwarnung.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				buttonWarnung_ActionPerformed();
			}
		});
		buttonweiter.setLabel("Weiter schalten");
		buttonweiter.setVisible(true);
		buttonweiter.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				buttonWeiter_ActionPerformed();
			}
		});
		
		JPanel rechteflaeche = new JPanel();
		rechteflaeche.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.VERTICAL;
        c.weightx = 1;
        c.gridy = 0;
        rechteflaeche.add(buttonautomatik,c);
        c.gridy = 1;
        rechteflaeche.add(buttonwarnung,c);
        c.gridy = 2;
        rechteflaeche.add(buttonweiter,c);
		
        frame1.addWindowListener(new WindowAdapter() { 
		      public void windowClosed(WindowEvent evt) { 
		    	 ampel_WindowClosed();
		      }
		});
		frame1.add(canvas,new GridBagFelder(0,0,1,1,0.65,1));
		frame1.add(rechteflaeche,new GridBagFelder(1,0,1,1,0.35,1));
		frame1.pack();
		frame1.setLocationRelativeTo(null);
		frame1.setVisible(true);
	}
}```

Ich konnte mit `c.gridy = 0;` usw. schon mal erreichen, dass die drei Buttons untereinander angezeigt werden.
Jedoch wird beispielsweise vollkommen ignoriert, dass ich dem Canvas links 65% Breite zuordne und dem Rechts 35%.
Dazu ist zu sagen das hier `new GridBagFelder(0,0,1,1,0.65,1)` hab ich mir als Abkürzung angelegt, um nicht immer alle Constraints untereinander schreiben zu müssen.
So sieht der Konstruktor dazu aus:
```public class GridBagFelder extends GridBagConstraints {
	
	public GridBagFelder(int x, int y, int width, int height, double weightX, double weightY) {
		this.fill = GridBagConstraints.BOTH;
	    this.gridx = x;
	    this.gridy = y;
	    this.gridwidth = width;
	    this.gridheight = height;
	    this.weightx = weightX;
	    this.weighty = weightY;
	}
}```

Nun geht meine Frage dahingehend, wie kann ich erreichen, dass das annähernd so aussieht wie auf dem ersten Bild?
Es wäre schön, wenn die Buttons sich oben rechts ausrichten und nicht so gigantisch viel Platz für nichts wegnehmen wie in dem Bild.

Wäre schön, wenn man mir ein paar Ideen geben könnte.

Vielen dank!
Lukas

dein Quellcode kommt dem Bild nicht ganz nahe,
mit Insets für Abstand und c.fill = GridBagConstraints.HORIZONTAL; statt c.fill = GridBagConstraints.VERTICAL;
schon eher,

damit alles nach oben geht ist ein weiteres ZwischenPanel mit BorderLayout North möglich,
oder ich verwende in solchen Fällen eine unsichtbare Komponente unten angefügt, die allen (vertikalen) freien Platz belegt


eine genaue Auftrennung 65% zu 35% halte ich nicht für besonders gut machbar,
GridBagLayout hat seine Grenzen, richtet sich sehr nach Preferred- und anderen Size der Komponenten,

ich habe es aber gerade mit

        p.setPreferredSize(new Dimension(0,0)); // ein Zwischenpanel mit BorderLayout NORTH

getestet, und da geht die die Aufteilung bei mir genau, auch bei Größenänderung korrekt wachsend + schrumpfend,
das sehe ich so ziemlich zum ersten Mal bei GridBagLayout, sonst alle möglichen Problemchen

PreferredSize auf 0 zu setzen habe ich glaube ich hier im Forum schon paar Mal vorgeschlagen, vielleicht auch bei ir,
aber überrascht mich immer noch selber :wink:
allzu offiziell kann das offensichtlich nicht sein, nur ein böser Workaround

edit:
wenn man aber wirklich mit fill und genauen Aufteilungen arbeitet kann man auch schon mal die Sonderwünsche der einzelnen Komponenten schlicht ausschalten,
nicht ganz abwegig

Hallo und vielen dank für Deine Antwort!
Ich erinnere mich, ich glaube ich war sogar derjenige, der schon mal mit Dimension 0,0 behandelt wurde. :smiley: Ich wusste es immer, dass Oracle Cheats in Java einbaut.

Wie dem auch sei.
Es ist fertig, alles funktioniert. Es sieht, wenn man nicht auf den Pixel genau hinsieht 1:1 so aus, wie vorher mit NullLayout.
Ich bin begeistert. Dass das so einfach geht, brillant. :slight_smile: Vielen Dank.

Das Endergebnis in Grafik sieht so aus. Links das neue:

Und in Quelltext sieht die Stelle so aus:

        rechteflaeche.setLayout(new BorderLayout());
        JPanel rfAufnahme = new JPanel();
        rfAufnahme.setLayout(new GridBagLayout());
        rechteflaeche.add(rfAufnahme,BorderLayout.NORTH);
        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.VERTICAL;
        c.weightx = 1;
        c.gridy = 0;
        rfAufnahme.add(buttonautomatik,c);
        c.gridy = 1;
        rfAufnahme.add(buttonwarnung,c);
        c.gridy = 2;
        rfAufnahme.add(buttonweiter,c);

        frame1.add(ampelflaeche,new GridBagFelder(0,0,1,1,0.65,1));
		frame1.add(rechteflaeche,new GridBagFelder(1,0,1,1,0.35,1));
		ampelflaeche.setPreferredSize(new Dimension(0,0));
		rechteflaeche.setPreferredSize(new Dimension(0,0));
		frame1.pack();
		frame1.setLocationRelativeTo(null);
		frame1.setVisible(true);```

Also ich habe einfach `rfAufnahme` auf JPanel draufgeklatscht und das nimmt alle Elemente auf. :)

Gruß
Lukas


Edit: Kleiner Trick meinerseits. Ich habe festgestellt, wenn ich alles verzerre und die Größe verändere heften die Buttons zwar oben aber sind x-Seitig irgendwo in der Mitte. Sowas wie NORTH-EAST hat BorderLayout leider nicht, also habe ich es nochmal geschachtelt, damit es rechts bleibt. :)