java-forum.org - Java programmieren aus Leidenschaft

Zurück   java-forum.org - Java programmieren aus Leidenschaft > Java-Forum FAQs > FAQ - Übersicht > Java-FAQ Beiträge > Bilder, GUI und was damit zusammenhängt

Antwort
Themen-Optionen Thema durchsuchen Ansicht
Alt 16.12.2011, 04:06   #1 (permalink)
Stammbenutzer
Megabyte
 
Benutzerbild von bERt0r
 
Registriert seit: 19.08.2011
Fachbeiträge: 2.201
Blog-Einträge: 3
Abgegebene Danke: 14
Erhielt 298 Danke für 293 Beiträge
Standard Das GroupLayout

GroupLayout für Homosapiens:
Das GroupLayout ist ein mächtiger LayoutManager, der leider oft als komplizierter missverstanden wird, als er eigentlich ist. Besonders GUI-Builder erzeugen meist sehr hässlichen Code mit dem Grouplayout, weshalb ich euch rate erst mal ein GroupLayout von Hand zu schreiben.
GroupLayout wurde mit dem Ziel geschaffen, von GUI Buildern verwendet zu werden, von Hand programmiert, liegt der Schreibaufwand etwa wie beim GridBagLayout.


Einem JPanel ein GroupLayout zu verpassen funktioniert erstmal nicht ganz genauso wie bei anderen LayoutManagern:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
JPanel panel=new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);

Vorsicht: Das GroupLayout wirft sehr schnell mal Exceptions wenn bei der initialisierung etwas schief gelaufen ist (z.B ein Komponent vergessen). Davon nicht abschrecken lassen! Andere LayoutManager kaschieren manche Ungereimtheiten und zeigen trotzdem was an. Das GroupLayout ist da wohl eher auf Perfektionismus ausgelegt: richtig oder gar nicht.

Zu den Komponenten:

Auch hier geht das GroupLayout wieder einen eigenen Weg: Komponenten werden nicht per panel.add(Component c) "hinzugefügt".
Man fasst die Komponenten in Gruppen zusammen und setzt diese in Beziehungen zueinander.
Anders als bei den GridBagConstraints wurde beim GroupLayout dieses "Beziehungen setzen" aber zweigeteilt: Man gibt die Größenverhältnisse einmal vertikal und einmal horizontal an:

Beispiel: Wir imitieren ein FlowLayout mit 3 Labels:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
JLabel label1=new JLabel("1");
JLabel label2=new JLabel("2");
JLabel label3=new JLabel("3");

1. Beziehungen auf vertikaler Ebene:
Wir wollen, dass alle 3 Labels in der gleichen Zeile stehen. Sehen wir von "Norden" aus auf unser Layout drauf (man beuge sich über den Bildschirm und blicke nach unten), sind die 3 Labels nebeneinander. Wenn wir 2 oder mehr Komponenten nebeneinander ausrichten wollen, benötigen wir eine ParallelGroup:

Java Code: Quelltext in neuem Fenster öffnen
1
ParallelGroup verticalGroup=layout.createParallelGroup();

Dieser ParallelGroup werden jetzt die Komponenten hinzugefügt:

Java Code: Quelltext in neuem Fenster öffnen
1
verticalGroup.addComponent(label1).addComponent(label2).addComponent(label3);

2. Beziehungen auf horizontaler Ebene:
Sehen wir von "Westen" auf unser Layout (man stelle sich links neben den Bildschirm und blicke hinein), sind die 3 Labels hintereinander. Dafür gibts die SequentialGroup:

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
SequentialGroup horizontalGroup=layout.createSequentialGroup;
 
horizontalGroup.addComponent(label1).addComponent(label2).addComponent(label3);
Zum Abschluss müssen wir unsere erstellten Gruppen noch dem Layout mit folgenden Methoden zuweisen:

Java Code: Quelltext in neuem Fenster öffnen
1
2
layout.setVerticalGroup(verticalGroup);
layout.setHorizontalGroup(horizontalGroup);

Jetzt noch panel in einen JFrame packen und fertig, unser erstes GroupLayout läuft!



Wichtig:Wenn du einen Komponenten nur zu einer Group addest, fliegt eine Exception und es wird nichts angezeigt!

VerticalFlowLayout
Aber was nützt uns ein FlowLayout? Schon so mancher hat den Bedarf nach einem VerticalFlowLayout angemeldet. Mit GroupLayout kein Problem: wir vertauschen einfach vertical- und horizontalGroup.

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
SequentialGroup verticalGroup=layout.createSequentialGroup();
verticalGroup.addComponent(label1).addComponent(label2).addComponent(label3);
 
ParallelGroup horizontalGroup=layout.createParallelGroup;
horizontalGroup.addComponent(label1).addComponent(label2).addComponent(label3);


Standard GUI
Wie siehts nun mit komplexeren Masken aus? Ich hab früher versucht aus zig verschiedenen, verschachtelten Panels jeweils mit eigenen einfachen LayoutManagern eine GUI zusammenzubasteln. Der Aufwand war enorm, die Übersichtlichkeit schrecklich, es war fehleranfällig und meist kam sowieso nicht das raus was gewollt war.
Mit dem GroupLayout kannst du dir das Panel verschachteln sparen, du verschachtelst die Groups.

Beispiel: Wir erweitern unser VerticalFlowGroupLayout: Da soll in jede Zeile noch zusätzlich ein Textfeld und ein Button rein:




1. Vertikale Group:
Wir stellen uns wieder vor, wir blicken von oben in unser Layout rein. Jetzt gibt’s zwei Betrachtungsweisen: Haben wir 3 Zeilen hintereinander, in denen je ein Label, ein Textfeld und ein Button nebeneinander stehen oder haben wir 3 Spalten nebeneinander mit jeweils 3 Labels, Textfeldern und Buttons hintereinander?
Die Entscheidung bleibt dir überlassen, ich werde es hier anhand des „3 Zeilen“ Ansatzes demonstrieren:

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
7
8
9
10
11
SequentialGroup verticalGroup=layout.createSequentialGroup();
        
        verticalGroup.addGroup(layout.createParallelGroup()
                .addComponent(label1).addComponent(textField1).addComponent(button1)
                );
        verticalGroup.addGroup(layout.createParallelGroup()
                .addComponent(label2).addComponent(textField2).addComponent(button2)
                );
        verticalGroup.addGroup(layout.createParallelGroup()
                .addComponent(label3).addComponent(textField3).addComponent(button3)
                );
2. Horizontale Group
Analog zur Vertikalen Group: Haben wir 3 Zeilen nebeneinander in denen Label, Textfeld und Button hintereinander stehen oder haben wir 3 Spalten hintereinander, in denen untereinander je 3 Labels, Textfelder oder Buttons stehen?
W man sich beim Vertikalen Teil für die Zeilen Denkweise entschieden hat, ist es mMn sinnvoll dabei zu bleiben:

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
7
8
9
10
11
12
ParallelGroup horizontalGroup=layout.createParallelGroup();
        
 
        horizontalGroup.addGroup(layout.createSequentialGroup()
                .addComponent(label1).addComponent(textField1).addComponent(button1)
                );
        horizontalGroup.addGroup(layout.createSequentialGroup()
                .addComponent(label2).addComponent(textField2).addComponent(button2)
                );
        horizontalGroup.addGroup(layout.createSequentialGroup()
                .addComponent(label3).addComponent(textField3).addComponent(button3)
                );

In meinem StandardFrame mit fixer Größe sieht das ganze nun aber so aus:



Die Komponenten füllen den gesamten Platz der aus – wir brauchen sowas wie einen Glue aus dem BoxLayout. Im GroupLayout heißt das Gap.

Gaps und Größenangaben
Erstens gibt’s da mal eine Komfortfunktion die man ich eigentlich immer aktiviert habe:
Java Code: Quelltext in neuem Fenster öffnen
1
layout.setAutoCreateGaps(true);

Damit kleben die Komponenten nicht mehr so aneinander, wie man das auch vom GridLayout her kennt.

Zu unserm Problem, wir können Gaps genauso wie Komponenten einer Gruppe hinzufügen:
Java Code: Quelltext in neuem Fenster öffnen
1
verticalGroup.addGap(Short.MAX_VALUE);

addGap erwartet einen Integer Wert als Parameter, der angibt wie groß der Gap sein soll. Short.MAX_VALUE liegt bei ca. 32000, so große Displays gibt’s noch nicht.

Man kann addGap aber auch 3 ints übergeben: addGap(int min,int pref, int max)
Man kann also Minimum, Preferred und Maximum Size einstellen. Das funktioniert genauso bei Komponenten:

Ändern wir den Code auf
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
verticalGroup.addGroup(layout.createParallelGroup()
.addComponent(label1)
. addComponent(textField1,20,20,20)
.addComponent(button1)
);

Wird unser Textfield1 immer genau 20 Pixel hoch sein.
Achtung: Die Größenangaben beziehen sich immer auf die Achse, in der sie gemacht werden. Angaben in der VerticalGroup beeinflussen nur die Höhe, Angaben in der HorizontalGroup nur die Breite.

Die Größenangaben manuell anzugeben ist allerdings kein sauberer Stil. Komponenten haben ja selber schon min, preferred und max Size Einstellungen, die werden dadurch einfach ignoriert. Um dem GroupLayout zu sagen, es soll immer auf eine dieser Methoden zurückgreifen gibt’s 2 Konstanten:
GroupLayout.DEFAULT_SIZE und GroupLayout.PREFERRED_SIZE

Beispiel:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
verticalGroup.addGroup(layout.createParallelGroup()
                .addComponent(label1)
                .addComponent(textField1,GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE,GroupLayout.PREFERRED_SIZE)
                .addComponent(button1)
                );

Jetzt kann das Textfeld maximal die Höhe seiner PreferredSize haben.


Beispiel: Wir wollen links unten in unserem Fenster einen OK Button einfügen.


Wir fügen einen Gap zwischen Zeile 3 und dem Ok Button ein:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
verticalGroup.addGap(0,0,Short.MAX_VALUE);
verticalGroup.addComponent(okButton);
 
horizontalGroup.addGroup(layout.createSequentialGroup()
                .addGap(0,0,Short.MAX_VALUE)
                .addComponent(okButton));

ein (0,0,Short.MAX_VALUE) Gap füllt soviel Platz aus, wie ihm zur Verfügung steht. Egal wie groß ihr das Fenster macht, der OK Button ist immer rechts unten.


Fortgeschrittenes:

Beispiel: Wir stellen die Font eines unserer Labels auf 80 und wollen, dass die Textfeld und Button in der Mitte der Zeile angezeigt werden. Wir setzten für unsere Textfelder unterschiedliche Preferred Sizes und wollen dass die Buttons alle schön untereinander stehen und gleich breit sein. Ausserdem soll das Layout nur so viel Platz wie nötig ausfüllen.



Erstmal setzten wir ganz normal die Preferred Size der Textfelder und die Font des Labels:

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
Font f = new Font( "Arial", Font.PLAIN, 80 );
label1.setFont(f);
 
textField1.setPreferredSize(new Dimension(70,20));
textField2.setPreferredSize(new Dimension(100,20));
textField3.setPreferredSize(new Dimension(130,20));

Problem 1: Die Komponenten einer Zeile der Höhe nach mittig ausrichten:
ParallelGroups kann man beim erzeugen einen Alignment Parameter übergeben. (Alignment. LEADING, TRAILING, CENTER oder BASELINE

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
verticalGroup.addGroup(layout.createParallelGroup(Alignment.CENTER)
.addComponent(label1)
.addComponent(textField1,GroupLayout.DEFAULT_SIZE,GroupLayout.DEFAULT_SIZE,GroupLayout.PREFERRED_SIZE)
.addComponent(button1)
);

Problem 2: Quasi ein Tabstopp für die Buttons. Wir haben nicht mehr einfach 4 Zeilen, wir haben 4 Zeilen und 2 Spalten.




Die HorizontalGroup muss deshalb verändert werden:
Wir stellen uns vor, wir schauen von „Westen“/Links auf unser Layout.
Da wir in unserem Layout 2 Spalten haben (Rote Rechtecke), die klar abgegrenzt hintereinander kommen sollen Brauchen wir erstmal eine SequentialGroup.
SequentialGroup horizontalGroup=layout.createSequentialGroup();

Jetzt betrachten wir erstmal nur das linke Rechteck (um das rechte kümmern wir uns nachher).
3 Zeilen übereinander mit je Label und Textfeld hintereinander oder 3 Labels übereinander, danach 3 Textfelder übereinander. (Wir machens auf die Zeilen Art).

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
7
8
9
10
11
12
13
ParallelGroup labelTextfieldGroup=layout.createParallelGroup()
                .addGroup(layout.createSequentialGroup()
                .addComponent(label1)
                .addComponent(textField1,GroupLayout.DEFAULT_SIZE,GroupLayout.DEFAULT_SIZE,GroupLayout.PREFERRED_SIZE)
                )
                .addGroup(layout.createSequentialGroup()
                .addComponent(label2)
                .addComponent(textField2,GroupLayout.DEFAULT_SIZE,GroupLayout.DEFAULT_SIZE,GroupLayout.PREFERRED_SIZE)
                )
                .addGroup(layout.createSequentialGroup()
                .addComponent(label3)
                .addComponent(textField3,GroupLayout.DEFAULT_SIZE,GroupLayout.DEFAULT_SIZE,GroupLayout.PREFERRED_SIZE)
                );

Dann noch die 4 Buttons übereinander, das ist wieder einfacher:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
ParallelGroup buttonGroup=layout.createParallelGroup(Alignment.TRAILING)
        .addComponent(button1)
        .addComponent(button2)
        .addComponent(button3)
        .addComponent(okButton);

Jetzt stöpseln wir die zwei roten Rechteck-Gruppen zusammen:

Java Code: Quelltext in neuem Fenster öffnen
1
horizontalGroup.addGroup(labelTextfieldGroup).addGroup(buttonGroup);

Problem 3: Den Buttons die gleiche Breite verpassen.

Dafür gibt’s die Funktion linkSize:
Java Code: Quelltext in neuem Fenster öffnen
1
layout.linkSize(SwingConstants.HORIZONTAL,button1,button2,button3,okButton);

SwingConstants.HORIZONTAL gibt an ob man die Breite oder die Höhe verlinken will. Danach kann man beliebig viele Komponenten hinzuschreiben (varargs).



Weiterführende Links:


Im Anhang die verwendeten Bilder und der gesamte Java-Code:
Miniaturansicht angehängter Grafiken
Das GroupLayout-flowlayout.png   Das GroupLayout-verticalflowlayout.png   Das GroupLayout-schoenegui.png   Das GroupLayout-fortgeschritten.png   Das GroupLayout-rechtecke.png   Das GroupLayout-haesslichegui.png   Das GroupLayout-textfeldhoehe.png   Das GroupLayout-okbutton.png  

Angehängte Dateien
Dateityp: java GlTutorial.java (4,0 KB, 37x aufgerufen)
bERt0r ist gerade online  
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Mit Zitat antworten
Danke sagen:
hypernikomen (20.12.2011), WPaul (02.12.2012)
Antwort

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
GroupLayout sh AWT, Swing, JavaFX & SWT 5 29.11.2011 04:44
(Applet) Applet starten...(+Timer?) fl_ex AWT, Swing, JavaFX & SWT 12 09.05.2011 10:22
Dynamisches GroupLayout (IllegalArgumentException) daWonderer AWT, Swing, JavaFX & SWT 0 03.04.2010 12:45
GroupLayout an un plötzlich is CardLayout Funktion tot? Daniel Sun AWT, Swing, JavaFX & SWT 10 19.08.2007 14:30


Lesezeichen

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are aus
Pingbacks are aus
Refbacks are aus


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:58 Uhr.


Powered by vBulletin® Version 3.8.6 (Deutsch)
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.2
Thanks for Smilies by smilies.4-user.de