GridBagLayout w akcji

Do tej pory w ChlebikClient wywoływane były zdarzenia oparte na pokazywaniu kolejnych okien JPane. Główna zaś ramka aplikacji została ‘narysowana’ w NetBeans. Kiedy zatem przyszła pora na stworzenie wewnętrznego okna z możliwością wyboru kolorów zaczęło się robić ciekawie, a konkretniej rzecz w zabawie z ułożeniem elementów wewnątrz ramki.

Do pozycjonowania elementów na kolejnych oknach aplikacji używane są tzw. layout managery. Zgodnie z nazwą zawiadują one rozmieszczeniem poszczególnych elementów – w zależności od potrzeb, używać można jednego z zaimplementowanych w Swingu. Co więcej, można nawet użyć IDE do ‘narysowania’ takiego okienka. Zaintrygował mnie jednak fragment ‘Thinking in Java’, gdzie autor napisał, że menadżer GridBagLayout jest bardzo trudny, ale daje też sporo możliwości. Stwierdziłem zatem, że na prostym przykładzie przećwiczę ten element, skoro niby jest trudny, to tym większa radocha z jego poznania.

Oto wstępny kod (bez importów i takich tam):

JFrame okienko = new JFrame("Testowe okienko");
GridBagLayout layout = new GridBagLayout();</code>

okienko.setLayout(layout);
okienko.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
okienko.setSize(250, 250);
okienko.setLocation(400, 400);
okienko.setVisible(true);

Wyjaśniać za wiele raczej nie trzeba. Tworzymy sobie ramkę – w aplikacji byłaby to instancja klasy JInternalFrame, ale jako, że to jest nasze jedyne okienko to musi ucieleśniać ‘klasę wyżej’ w hierarchii kontenerów. Domyślnie kończymy działanie aplikacji po zamknięciu ramki, ustawiamy jej wymiary i położenie. Należy zwrócić uwagę, że tworzymy już obiekt GridBagLayout, choć na razie z braku elementów wewnątrz ramki niewiele z tego wynika.

Naszym celem jest stworzenie prostego wybierania kolorów. Każdy element aplikacji może mieć przypisany inny kolor niż domyślny. Dlatego też wylistujemy dostępne opcjew takiej formie:

JLabel (nazwa) JLabel (pusta, tylko tło z kolorem) JButton (przycisk zmień)

W ten sposób wypełnimy całą ramkę. Do pracy!

Przy dodawaniu elementów do kontenera, którym zawiaduje GridBagLayout, możemy przypisać do każdego takiego elementu obiekt GridBagConstraints, który odpowiednio ustawi dany element w kontenerze. Cała idea tego menadżera layoutu polega na podzieleniu całego kontenera na ‘komórki’, w które wkładamy następnie elementy. Przypomina to budowanie stron WWW w oparciu o tabelki i zasadniczo porównanie jest dość trafne, z tym tylko, że daje o wiele więcej możliwości ustawienia położenia.

Jak pokazałem powyżej, zależało mi na 3 kolumnach, w których umieściłbym elementy JLabel i JButton. Oczywiście powinny być one wyrównane oraz posiadać dokładnie te same wymiary. Do kodu dodałem wywołanie metody pack(), która rozszerza kontener do zadanych rozmiarów, a kiedy ich nie ma – do rozmiaru odpowiedniego, aby zmieściły się w nim wszystkie elementy (i jednocześnie były widoczne). Zatem możemy zakomentować linijkę określającą rozmiar naszej ramki, a komponenty wewnątrz niej rozepchają ją do odpowiednich rozmiarów.

Tworzymy obiekt GridBagConstraints i następnie przypisujemy jego właściwości insets odpowiedni obiekt, który określa ‘oddalenie’ danego elementu od krawędzi ‘komórki’. Komórki, gdyż następnymi własnościami obiektu GridBagConstraintsgridx i gridy. One określają w której komórce ma znaleźć się wskazany element – numeracja zaczyna się w obu przypadkach od 0 i oznacza górny lewy róg ramki. Kiedy mamy już tak określony obiekt, tworzymy nową etykietę i dodajemy ją do istniejącej ramki (poprzez metodę add kontenera). Oto zatem fragment kodu:

GridBagConstraints ogranicznik = new GridBagConstraints();
ogranicznik.insets = new Insets(5, 10, 5, 5);
ogranicznik.gridx = 0;
ogranicznik.gridy = 0; </code>

JLabel kolor1name = new JLabel("kolor1");
kolor1name.setBorder(javax.swing.BorderFactory.createLineBorder(Color.BLUE, 1));
okienko.add(kolor1name, ogranicznik);

okienko.pack();

Dodam tylko, że parametry konstruktora obiektu Insets oznaczają kolejno górę, lewo, dół i prawo (czyli odwrotnie niż w przypadku CSSa). Do etykiety dodałem też ramkę, aby było dobrze widać efekty naszych poczynań.

1kolor

Ramka została utworzona w taki oto sposób (głównie chodzi o szerokość), aby zmieścić podstawowe elementy górnej belki (ikonkę, część tytułu, przyciski), a w środku mamy naszą etykietę. Wygląda to jednakże niezaszczególnie zatem dopiszmy do kodu dalszą część:

ogranicznik.gridx = 1;
JLabel kolor1bg = new JLabel("kolor1tło");
kolor1bg.setBorder(javax.swing.BorderFactory.createLineBorder(Color.RED, 1));
okienko.add(kolor1bg, ogranicznik);

ogranicznik.gridx = 2;
JButton kolor1zmien = new JButton("Zmień");
okienko.add(kolor1zmien, ogranicznik);

I tak to oto powinno wyglądać:

2kolor

Jak widać przy dodawaniu kolejnych elementów zmieniam tylko wartość własności gridx, co powoduje rozciąganie całej ramki, gdyż powiększa się ilość komórek ‘w poziomie’. Dodajmy teraz drugi wiersz takich samych elementów – wystarczy skopiować kod zmieniając nazwy obiektów i modyfikując na początek wartość gridy na 1. Oto efekt:

3kolor

Na zakończenie omówimy jeszcze jedną rzecz – położenie elementu w konkretnej ‘komórce’. Otóż w obiekcie GridBagConstraints mamy statyczne zmienne, które określają położenie elementu. Jeśli zatem chcemy, aby np. nasza etykieta kolor1 znalazła się w górnym-lewym rogu swej komórki, wówczas w obiekcie GridBagConstraints modyfikujemy własność anchor na GridBagConstraints.NORTHWEST i efekt gotowy! Oczywiście wtedy ustawiamy właśność insets na wartości domyślne (0,0,0,0). Tak to wygląda po uruchomieniu:

4kolor

Jak zatem widać nie taki diabeł straszny jak go malują. Oczywiście to taki mały przedsmak – polecam zapoznanie się z dokumentacją, która z pewnością pokaże jeszcze masę możliwości związanych z tym menadżerem layoutu. Jak to mówią – Position is everything 🙂

Advertisements

2 thoughts on “GridBagLayout w akcji

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s