Swing GridBagLayout: Links-nach-rechts Orientierung statt zentriert

  • Themenstarter Themenstarter Jocbe
  • Beginndatum Beginndatum
J

Jocbe

Gast
Hallo,
nach ein wenig Erfahrung mit anderen Sprachen wie VB und C++ habe ich mich jetzt Java zugewendet. Jetzt möchte bzw. muss ich Programme mit einer GUI programmieren, allerdings ohne einen visual editor zu verwenden (ich habe in diesem Fall keine Wahl). Meine Entscheidung fiel auf swing mit einem GridBagLayout.

Ich habe etwas herumprobiert und bin auf das Problem gestoßen, dass die Steuerelemente aus irgend einem Grund immer zentriert sind. Ich schaffe es nicht, die Steuerelemente am linken Fensterrand zu verankern.
Ich hab unten mal den Code gepostet, mit dem ich bisher experimentiert habe (nicht der sauberste, aber ich experimentiere ja noch). Ich verwende für die Tests übrigens Netbeans:
Java:
package guitest;

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


/**
 *
 * @author xxx
 */
public class GUITest {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        JFrame mFrm = new JFrame("Window title");
        JPanel mPan = new JPanel(new GridBagLayout());
        
        mFrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mFrm.setSize(400,300);
        mFrm.setVisible(true);
        mFrm.getContentPane().setLayout(new BorderLayout());
        mFrm.getContentPane().add(mPan, BorderLayout.NORTH);
        
        mPan.setLayout(new GridBagLayout());
        
        
        GridBagConstraints c = new GridBagConstraints();
        
        
        JButton lbl1 = new JButton("label1");
        JButton lbl2 = new JButton("label2");
        JButton lbl3 = new JButton("label3");
        JButton lbl4 = new JButton("label4");
        JButton lbl5 = new JButton("label5");
        
        c.fill = GridBagConstraints.HORIZONTAL;
        c.anchor = GridBagConstraints.NORTHWEST;
        c.insets = new Insets(1,1,1,1);
        c.gridx = 0;
        c.gridy = 0;
        mPan.add(lbl1, c);
        c.gridx = 2;
        c.gridy = 0;
        mPan.add(lbl2, c);
        c.gridx = 1;
        c.gridy = 1;
        mPan.add(lbl3, c);
        c.gridx = 0;
        c.gridy = 2;
        c.gridwidth = 2;
        mPan.add(lbl4, c);
        c.gridx = 0;
        c.gridy = 3;
        c.gridwidth = 3;
        mPan.add(lbl5, c);
        
    }
}

Ich habe schon etwas recherchiert, es dennoch nicht zum laufen bekommen, obwohl ich denke, dass es ja eigentlich nicht so schwer sein sollte. Wie kann man also die Steuerelemente so anordnen, dass sie sich an der oberen linken Ecke orientieren?

Vielen Dank im Voraus!
MfG,
Jocbe
 
Hi,

folgendes Problem: GridBagConstraints zentriert das Grid immer auf der verfügbaren Fläche (mir ist nicht bekannt dass man das Behaviour ändern kann).
Was man hingegen sehr wohl machen kann ist den Layoutmanager des umgebenden Containers zu ändern. Versuche mal folgendes:

Ersetze in deinem Code:

Java:
mFrm.getContentPane().setLayout(new BorderLayout());
mFrm.getContentPane().add(mPan, BorderLayout.NORTH);

durch:

Java:
mFrm.setLayout(new FlowLayout(FlowLayout.LEADING));
mFrm.add(mPan);


Das sollte funktionieren. Ich hab' es grade hier auf meinem Rechner getestet, die Komponenten des GridBagLayouts werden in der oberen linken Ecke des Fensters angeordnet.

Warum geht es mit einem BorderLayout nicht? BorderLayout vergibt 5 Bereiche: North, East, South, West, und Center. Dabei erstreckt sich die NORTH-Komponente vom linken bis zum rechten Rand des Zeichenfensters. Das war bei dir der Fall. IN diesem Bereich hinein hast du dein GridBag gepackt und das zentriert sich automatisch. Darum sah es so aus als ob die Komponenten oben in der Mitte kleben würden.


Ich hoffe das beantwortet deine Frage 🙂


Gruß,



Alan
 
folgendes Problem: GridBagConstraints zentriert das Grid immer auf der verfügbaren Fläche (mir ist nicht bekannt dass man das Behaviour ändern kann).
Dann frage ich mich, warum du hier so ein "behaviour" an den Tag legst... 😱 (Finde übertriebene Anglizismen total doof.)
Wenn du keine Ahnung hast, einfach nichts posten. 😉

Ach, und übrigens: man kann das Verhalten anpassen. Und das unheimlich vielfältig.
Lies mal Camino's Link.
 
@L-ectron-X: Der Ausrutscher mit dem Englisch tut mir leid, mit anderen Programmierern unterhalte ich mich im "echten" Leben fast ausschließlich mit englischen Ausdrücken... entschuldige bitte.

Was meine Lösung betrifft: sie funktioniert garantiert, ich habe es selbst getestet. Mir waren die Tipps aus dem Tutorial-Link bekannt. Ich habe Verschiedenes ausprobiert, aber innerhalb des vorhandenen BorderLayouts ein GridBag-Layout in der North-Komponente so einzubetten, dass das Grid linkszentriert dargestellt wird (und damit meine ich nicht über die gesamte Breite gestreckt, sondern wirklich am linken Rand ausgerichtet) wie es gefragt wurde, habe ich nicht hinbiegen können.
Daher erschien es mir die einfachste Lösung (gerade wenn der Fragesteller erst mit Swing anfängt) anstelle des BorderLayouts einfach ein FlowLayout zu verwenden. Ich wollte nur helfen. Wenn jemand eine Lösung findet, die sich rein mit den GridBagConstraints machen lässt und das Grid trotzdem links ausrichtet, dann würde ich diese gerne sehen 🙂

mfG

Alan
 
Ich schaffe es nicht, die Steuerelemente am linken Fensterrand zu verankern.
Verankern ist das richtige Wort: gbc.anchor = GridBagConstraints.WEST;

Hier ein kleines Beispiel:
Java:
public class AlignTest extends JFrame {

	private JPanel contentPane;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					AlignTest frame = new AlignTest();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public AlignTest() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));
		
		JPanel panel = new JPanel();
		panel.setBorder(new LineBorder(new Color(0, 0, 0), 3));
		contentPane.add(panel, BorderLayout.NORTH);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{0, 0};
		gbl_panel.rowHeights = new int[]{0, 0};
		gbl_panel.columnWeights = new double[]{0.0, Double.MIN_VALUE};
		gbl_panel.rowWeights = new double[]{0.0, Double.MIN_VALUE};
		panel.setLayout(gbl_panel);
		
		JLabel lblHalloWelt = new JLabel("Hallo Welt");
		lblHalloWelt.setBorder(new LineBorder(new Color(0,0,0),1));
		GridBagConstraints gbc_lblHalloWelt = new GridBagConstraints();
		gbc_lblHalloWelt.anchor = GridBagConstraints.WEST;
		gbc_lblHalloWelt.gridx = 0;
		gbc_lblHalloWelt.gridy = 0;
		panel.add(lblHalloWelt, gbc_lblHalloWelt);
	}

}
 
Danke für die zahlreichen Antworten!

Ich habe verschiedenes Versucht, mit dem BorderLayout hat es jedoch nach wie vor nicht geklappt.
Mit dem Vorschlag von Alan funktioniert es genau so, wie ich es mir vorgestellt habe, vielen Dank dafür also.

Mit .anchor hat es leider nicht geklappt; es scheint in meinem Fall ja das ganze JPanel in der Form zentriert zu werden, nicht die einzelnen Steuerelement im JPanel.

Caminos Link sieht interessant aus, auch sonst, fürs programmieren mit dem GridBagLayout - ich sehe ihn mir auf jeden Fall noch genauer an.

MfG
Jocbe
 
Mit .anchor hat es leider nicht geklappt; es scheint in meinem Fall ja das ganze JPanel in der Form zentriert zu werden, nicht die einzelnen Steuerelement im JPanel.
Code:
anchor
alleine reicht wohl nicht, deshalb noch der Hinweis auf
Code:
weight
. Dort kann man Werte (double) zwischen 0.0 und 1.0 setzen und die regeln den überschüssigen Platz, wenn z.B. das Panel grösser ist, als die daraufliegenden Komponenten, oder wenn sich die Grösse von Panel bzw. Frame ändert. Normalerweise reicht es, wenn du bei allen Komponenten die weight-Werte auf 0.0 lässt, und nur bei der letzten Komponente in Reihe oder Spalte den Wert auf 1.0 setzt. Dann noch mit dem richtigen anchor (WEST oder NORTHWEST), dann müssten die Komponenten alle links bzw. links oben angeordnet sein. Kannste ja mal ein bisschen rumprobieren. Steht auch in dem Link, bestimmt noch etwas besser und ausführlicher erklärt.
 
Camino hat gesagt.:
Code:
anchor
alleine reicht wohl nicht, deshalb noch der Hinweis auf
Code:
weight
Ja, du hast natürlich recht, so geht es in dem meisten Fällen einwandfrei. Nur in dem Fall, dass man dann doch mal ausschließlich Steuerelement hat, die ihre Größe nicht verändern sollen, klappt es nicht mehr so gut. Diesen Fall hatte ich versucht hier zu klären; aber meistens wird man vermutlich doch zu
Code:
weight
greifen.
Oder gibt es in diesem Fall denn Vor- bzw. Nachteile des BorderLayouts gegenüber dem FlowLayout?
 
Wenn du nicht das am rechten Rand liegende Element weight 1 geben willst, musst du ein anderes Element auf weight 1 oder zumindest fill horizontal setzten, damit es sich vergrößert. Wenn zu viel Platz da ist, muss ja irgend ein Component den dann ausfüllen.
Java:
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));
		
		JPanel panel = new JPanel();
		panel.setBorder(new LineBorder(new Color(0, 0, 0), 3));
		contentPane.add(panel, BorderLayout.NORTH);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{0, 0, 0, 0};
		gbl_panel.rowHeights = new int[]{0, 0, 0};
		gbl_panel.columnWeights = new double[]{0.0, 1.0, 0.0, Double.MIN_VALUE};
		gbl_panel.rowWeights = new double[]{1.0, 0.0, Double.MIN_VALUE};
		panel.setLayout(gbl_panel);
		
		JLabel lblHalloWelt = new JLabel("Hallo Welt");
		lblHalloWelt.setBorder(new LineBorder(new Color(0,0,0),1));
		GridBagConstraints gbc_lblHalloWelt = new GridBagConstraints();
		gbc_lblHalloWelt.insets = new Insets(0, 0, 5, 5);
		gbc_lblHalloWelt.anchor = GridBagConstraints.WEST;
		gbc_lblHalloWelt.gridx = 0;
		gbc_lblHalloWelt.gridy = 0;
		panel.add(lblHalloWelt, gbc_lblHalloWelt);
		
		JPanel panel_1 = new JPanel();
		GridBagConstraints gbc_panel_1 = new GridBagConstraints();
		gbc_panel_1.insets = new Insets(0, 0, 5, 5);
		gbc_panel_1.fill = GridBagConstraints.BOTH;
		gbc_panel_1.gridx = 1;
		gbc_panel_1.gridy = 0;
		panel.add(panel_1, gbc_panel_1);
		
		JLabel lblHalloMars = new JLabel("Hallo Mars");
		lblHalloMars.setBorder(new LineBorder(new Color(0, 0, 0)));
		GridBagConstraints gbc_lblHalloMars = new GridBagConstraints();
		gbc_lblHalloMars.insets = new Insets(0, 0, 5, 0);
		gbc_lblHalloMars.anchor = GridBagConstraints.EAST;
		gbc_lblHalloMars.gridx = 2;
		gbc_lblHalloMars.gridy = 0;
		panel.add(lblHalloMars, gbc_lblHalloMars);
 
Ja, du hast natürlich recht, so geht es in dem meisten Fällen einwandfrei. Nur in dem Fall, dass man dann doch mal ausschließlich Steuerelement hat, die ihre Größe nicht verändern sollen, klappt es nicht mehr so gut.
Hmm, versteh ich jetzt nicht so richtig. Die Grösse der Steuerelemente (meinst du damit die Komponenten, die auf das Panel gesetzt werden?) kannst du doch mit setPreferredSize und setMinimumSize festlegen. Das hat mit der Anordnung auf dem JPanel, auf dem sie dann liegen, erstmal nicht viel zu tun.

Oder gibt es in diesem Fall denn Vor- bzw. Nachteile des BorderLayouts gegenüber dem FlowLayout?
Die Frage versteh ich jetzt auch nicht. Du legst ein JPanel mit GridBagLayout entweder in ein BorderLayout oder in ein FlowLayout. Wichtig ist dann erstmal, was du in dem GridBagLayout veranstaltest.
 
Bitte entschuldigt die späte Antwort!

@Camino
Ok, klar, ich hab da irgendwie um die Ecke gedacht. Hast natürlich recht, mit anchor + weight geht es auch mit dem BorderLayout.

Camino hat gesagt.:
Die Frage versteh ich jetzt auch nicht. Du legst ein JPanel mit GridBagLayout entweder in ein BorderLayout oder in ein FlowLayout. Wichtig ist dann erstmal, was du in dem GridBagLayout veranstaltest.
Naja, ich weiß ja nicht (wie gesagt, ich bin ziemlicher Anfänger, was Java angeht), es könnte ja sein, dass ein Layout vielleicht CPU-intensiver oder instabiler ist, oder ähnliches. Vielleicht gibt es ja einen Grund das eine dem anderen vorzuziehen, wenn man beide verwenden kann 🙂
 
Hmmm, darüber hab ich mir eigentlich noch keine Gedanken gemacht. Ich denke auch nicht, daß das bei den LayoutManagern eine so wichtige Rolle spielt. Wichtiger sind wahrscheinlich die Überlegungen, was man darstellen möchte und mit welchem LayoutManager man das erreichen kann. Also, ob und wie man schachtelt, wie umständlich oder übersichtlich man seine GUI aufbaut usw. Es kann auf jeden Fall nicht schaden, sich die im JDK zur Verfügung gestellten LayoutManager mal genauer anzuschauen und ein bisschen damit "herumzuspielen". Dann findest du auch schneller raus, welche/n LayoutManager du für welchen Fall brauchst.
 

Neue Themen


Zurück
Oben