BorderLayout

Koziołek

1 Podstawy ogólnie
2 BorderLayout informacje podstawowe
3 BorderLayout sposób użycia
     3.1 Tworzenie BorderLayout
     3.2 Dodawanie elementów
4 Podsumowanie
5 Zobacz też

Pracując z komponentami Swing dość szybko zorientujemy się, że ich ułożeniem można sterować na kilka sposobów. Najprostszym z nich jest ręczne ustawianie każdego z komponentów w kontenerze. By mieć taką możliwość musimy wyzerować Layout Managera, danego kontenera:

container.setLayout(null);

Takie podejście ma wiele wad. Największą z nich jest konieczność ręcznego wpisywania położeń dla wszystkich komponentów w kontenerze. Jak wiadomo każdy nadmiarowy kod jest przyczyną nowych ciekawych błędów. Błędów chcemy unikać.
W tym artykule przedstawiony będzie najprostszy z Layout Managerów java.awt.BorderLayout.

Podstawy ogólnie

Jeżeli chcemy zrozumieć jak działa BorderLayout musimy najpierw zrozumieć zasady działania Layout Managera (LM). Najprościej rzecz ujmując LM zajmuje się rozmieszczeniem komponentów w kontenerze. Sposób w jaki to robi jest uzależniony od jego implemetacji, ale wszystkie LM realizują pewien wspólny algorytm:

  1. Obliczają maksymalną/preferowaną/minimalną wielkość kontenera.
  2. Rozmieszczają komponenty w kontenerze.

Sam kontener może znajdować się w prawidłowym (ang. valid) lub nieprawidłowym (ang. invalid) stanie. Domyślnie kontener znajduje się w stanie nieprawidłowym. Stan kontenera można sprawdzić wywołując metodę isValid(). Jeżeli chcemy ustawić stan kontenera na poprawny należy wywołać metodę validate(). Jest ona rekurencyjna i dokona ona sprawdzenia stanu dla wszystkich dzieci. Nie należy jej jednak wywoływać samemu. Prawidłowym rozwiązaniem jest wywołanie metody pack() kontenera.

BorderLayout informacje podstawowe

BorderLayout jest najprostszym z LM. Jest też domyślnym LM dla komponentów. Co to oznacza dla nas? Po pierwsze z obiektem BorderLayout spotykamy się już na samym początku naszej przygody z pakietami awt i swing. Powoduje to, że wielu początkujących programistów popełnia trudne do wykrycia błędy lub irytuje się "błędnym" zachowaniem programu.
BorderLayout dzieli przestrzeń kontenera na pięć podstawowych regionów:

  1. NORTH - region obejmuje domyślnie 1/3 wysokości kontenera od góry i całą jego szerokość.
  2. SOUTH - region obejmuje domyślnie 1/3 wysokości kontenera od dołu i całą jego szerokość.
  3. WEST - region obejmuje domyślnie 1/3 wysokości kontenera pomiędzy NORTH i SOUTH i 1/3 jego szerokość od lewej krawędzi.
  4. EAST - region obejmuje domyślnie 1/3 wysokości kontenera pomiędzy NORTH i SOUTH i 1/3 jego szerokość od prawej krawędzi.
  5. CENTER - region obejmuje domyślnie 1/3 wysokości kontenera pomiędzy NORTH i SOUTH i 1/3 jego szerokość pomiędzy WEST i EAST. Inaczej mówiąc środek kontenera.

Prosty program (nie najlepszy, ale nie o to chodzi) ilustrujący rozłożenie komponentów:

package eu.runelord.programmers.java.borderlayouttutorial;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;


class BorderLayoutExample extends JFrame {

	private static final long serialVersionUID = 5542988826027886015L;

	public static void main(String[] args) {
		BorderLayoutExample borderLayoutExample = new BorderLayoutExample();
		borderLayoutExample.setVisible(true);
	}

	public BorderLayoutExample() {
		init();
	}
	
	private void init() {
		BorderLayout borderLayout = new BorderLayout();
		JButton n = new JButton("NORTH"), s = new JButton("SOUTH"), w = new JButton(
				"WEST"), e = new JButton("EAST"), c = new JButton("CENTER");
		setLayout(borderLayout);
		setTitle("Przykład BorderLayout");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		add(n);
		add(s);
		add(w);
		add(e);
		add(c);
		borderLayout.addLayoutComponent(n, BorderLayout.NORTH);
		borderLayout.addLayoutComponent(s, BorderLayout.SOUTH);
		borderLayout.addLayoutComponent(w, BorderLayout.WEST);
		borderLayout.addLayoutComponent(e, BorderLayout.EAST);
		borderLayout.addLayoutComponent(c, BorderLayout.CENTER);
		pack();		
	}
}

BorderLayout sposób użycia

Użycie BorderLayout jest stosunkowo proste. Może on służyć jako podstawowy LM dla wielu komponentów. Należy jednak pamiętać o tym, że:

  1. BorderLayout ignoruje wartości minimumSize i maximumSize dla wszytkich elementów.
  2. Ignoruje wartość preferredSize dla komponentu CENTER w obu osiach.
  3. Ignoruje wartość preferredSize dla komponentów WEST, CENTER, EAST w osi pionowej.
  4. Kolejność znikania elementów jeżeli zmniejszamy okno:
  5. w pionie
  6. WEST, CENTER, EAST znikają razem.
  7. SOUTH "chowa się" pod NORTH.
  8. NORTH, aż do osiągniecia wysokości nie mniejszej niż domyślna majmniejsza wysokść dla systemu (w windowsie pasek z nazwą okna)
  9. w poziomie
  10. Znika tylko CENTER. Minimalna szerokość okna jest nie mniejsza niż domyślna najmniejsza szerokość dla systemu.
    Te własności BorderLayout powodują też niestety wiele problemów. Z tego powodu czasami warto porzucić go dla innych, dających większą swobodę LM. Przejdźmy teraz do trochę bardziej szczegółowych zagadnień.

Tworzenie BorderLayout

W przykładzie pierwszym można zobaczyć, że stworzenie prostego BorderLayoout nie wymaga od nas zbyt wiele pracy. Klasa ma konstruktor domyślny. Ma też i drugi konstruktor BorderLayout(int hgap, int vgap). Parametry oznaczają odległość pomiędzy poszczególnymi elementami odpowiednio w pionie i poziomie. Efekty zastosowania tego konstruktora ilustruje poniższy program:

package eu.runelord.programmers.java.borderlayouttutorial;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;

class BorderLayoutExample2 extends JFrame {

	private static final long serialVersionUID = 5542988826027886015L;

	public static void main(String[] args) {
		BorderLayoutExample2 borderLayoutExample = new BorderLayoutExample2();
		borderLayoutExample.setVisible(true);
	}
	
	public BorderLayoutExample2() {
		init();
	}
	
	private void init() {
		BorderLayout borderLayout = new BorderLayout(10,10);
		JButton n = new JButton("NORTH"), s = new JButton("SOUTH"), w = new JButton(
				"WEST"), e = new JButton("EAST"), c = new JButton("CENTER");
		setLayout(borderLayout);
		setTitle("Przykład BorderLayout2");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		add(n);
		add(s);
		add(w);
		add(e);
		add(c);
		borderLayout.addLayoutComponent(n, BorderLayout.NORTH);
		borderLayout.addLayoutComponent(s, BorderLayout.SOUTH);
		borderLayout.addLayoutComponent(w, BorderLayout.WEST);
		borderLayout.addLayoutComponent(e, BorderLayout.EAST);
		borderLayout.addLayoutComponent(c, BorderLayout.CENTER);
		pack();		
	}
}

Dodawanie elementów

Przyjrzyjmy się teraz dokładniej temu jak dodawać elementy do BorderLyaout. Na początek ważna uwaga ten LM działa według zasady jeden boks jeden komponent. Jeżeli chcemy zatem dodać więcej komponentów do danego boksu mamy dwie możliwości. Pierwsza to zmienić LM, druga napisać własny prywatny komponent, który będzie przechowywał nasze bazowe komponenty.
Patrząc na kod z pierwszego przykładu dość łatwo można zauważyć, że dodanie komponentu to dwie oddzielne czynności. Pierwsza to dodanie komponentu do kontenera za pomocą metody add(Component). Druga to ustawienie komponentu w LM za pomocą addLayoutComponent(component, constrains). Tu kod aż prosi się o udoskonalenie i optymalizację. Przyjrzyjmy się teraz kolejnemu przykładowemu programowi.

package eu.runelord.programmers.java.borderlayouttutorial;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;

class BorderLayoutExample3 extends JFrame {

	private static final long serialVersionUID = 5542988826027886015L;
	private BorderLayout borderLayout;
	private JButton n;
	private JButton s;
	private JButton w;
	private JButton e;
	private JButton c;

	public static void main(String[] args) {
		BorderLayoutExample3 borderLayoutExample = new BorderLayoutExample3();
		borderLayoutExample.setVisible(true);
	}

	public BorderLayoutExample3() {
		init();
	}

	private void init() {
		borderLayout = new BorderLayout(1, 1);
		n = new JButton("NORTH");
		s = new JButton("SOUTH");
		w = new JButton("WEST");
		e = new JButton("EAST");
		c = new JButton("CENTER");
		setLayout(borderLayout);
		setTitle("Przykład BorderLayout2");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		addComponent(n, BorderLayout.PAGE_START);
		addComponent(s, BorderLayout.SOUTH);
		addComponent(w, BorderLayout.WEST);
		addComponent(e, BorderLayout.EAST);
		addComponent(c, BorderLayout.CENTER);
		pack();
	}

	private void addComponent(JComponent component, Object constrains) {
		add(component);
		borderLayout.addLayoutComponent(component, constrains);
	}
}

Przeniosłem tu kod dodający komponenty do osobnej metody. Dodatkowo pojawia się nowa stała PAGE_START. Jest ona odpowiednikiem NORTH tak samo jak BEFORE_FIRST_LINE. Lista odpowiedników znajduje się w dokumentacji[#]_.

Podsumowanie

BorderLayout jest najprostszym z layout managerów dostępnych w pakiecie awt. Można go też z powodzeniem stosować z komponentami pakietu Swing. Zawiera on proste reguły pozwalające na szybkie i zrozumiałe rozmieszczenie komponentów w kontenerze. Dzięki temu można go w miarę swobodnie stosować w wielu projektach. Z drugiej strony BorderLayout ma też wiele ograniczeń, które powodują, że nie stanowi on panaceum na wszystkie problemy. Najbardziej widocznym ograniczeniem jest możliwość dodania tylko jednego komponentu do boksu.

Zobacz też

BoxLayout
CardLayout
FlowLayout
GridBagLayout
GridLayout
GroupLayout
SpringLayout

.. [#] Pełna dokumentacja klasy BorderLayout w javie 1.5 znajduje się pod adresem: http://java.sun.com/j2se/1.5.0/docs/api/java/awt/BorderLayout.html

0 komentarzy