Освоюємо Java/Менеджери розташування

Менеджери розташування (Layout Managers, перекл. також як диспетчери компонування або менеджери компонування) розміщують графічні компоненти у контейнері відповідно до певної схеми розташування (layout scheme). Кожен контейнер (фрейм, панель тощо) має менеджер розташування по замовчуванню.

Навіщо потрібні менеджери розташування?

ред.

Розташовувати компоненти інтерфейсу користувача можна і вручну, проте це доволі трудомістка процедура, крім того, що Вам необхідно задати координати та розміри компонент, ви повинні, також, передбачити як змінюватиметься графічний інтерфейс при зміні розміру вікна. Для полегшення цієї задачі і створено ряд класів менеджерів розташування, які більшість рутинної роботи беруть на себе.

Для додавання менеджера до вашого контейнера використовується метод setLayout(). Наприклад:

setLayout (new BorderLayout());

Розглянемо детальніше роботу з кожним менеджером розташування.

FlowLayout

ред.

FlowLayout – найпростіший із менеджерів розташування, який застосовують по замовчуванню у деяких контейнерах, зокрема в JPanel. Він розміщує елементи один за одним справа на ліво і зверху вниз. Подібно до того як текстовому редакторі розміщуються слова в тексті. Менеджер також дозволяє здійснювати вирівнювання вмісту контейнера по ліву та праву сторону і по центру (LEFT, RIGHT, CENTER). Недоліком його є непередбачуваність інтерфейсу програми. Так якщо наприклад у Вас розташовано в ряд 5-ть кнопок, то зменшення розміру вікна призводить до переносу частини кнопок вниз (дивіться приклад далі).

Існує три конструктори FlowLayout:

FlowLayout(); 
FlowLayout(int how); 
FlowLayout(int how, int horz, int vert);

Перший застосовує схему розташування по замовчуванню, тобто по центрі. У другому випадку задається спосіб вирівнювання, наприклад, можна задати вирівнювання FlowLayout.Left. В третьому конструкторі крім вирівнювання вказуються відстань по горизонталі та по вертикалі між компонентами.

Наступна програма демонструє розміщення компонентів:

 
Результат виконання FlowLayoutExample.java
 
Результат виконання FlowLayoutExample.java при зменшенні ширини вікна
import java.awt.FlowLayout;
import java.awt.LayoutManager;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class FlowLayoutExample {

    public static void main(String[] args) {
     ProgramFrame frame = new ProgramFrame();
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}


class ProgramFrame extends JFrame{
    ProgramFrame(){
        //задаємо розмір фрейму
        setSize(450, 150);
        //створюємо кнопки
        JButton red = new JButton("Червоний");
        JButton yellow=new JButton("Жовтий");
        JButton green = new JButton("Зелений");
        JButton blue=new JButton("Синій");
        JButton black = new JButton("Чорний");
        JButton white=new JButton("Білий");
        // створюємо панель, на якій будуть розміщені кнопки
        JPanel panel = new JPanel();
        // встановлюємо менеджер FlowLayout
        // з вирівнюванням вліво 
        // якщо пропустити наступний рядок, то по замовчуванню буде по центру
        panel.setLayout (new FlowLayout(FlowLayout.LEFT));
        // додаємо панель у фрейм
        this.add(panel);
        // додаємо кнопки на панель
        
        panel.add(red);
        panel.add(yellow);
        panel.add (green);
        panel.add (black);
        panel.add (white);
       
    }
}

BorderLayout

ред.

BorderLayout розташовує об’єкти в одну з п’яти географічних позицій (північ, південь, захід, схід і центр), що представлені константами в класі BorderLayout: NORTH, SOUTH, EAST, WEST, CENTER. BorderLayout є менеджером для об’єктів JWindow та JFrame.

BorderLayout має два конструктори:

BorderLayout();
BorderLayout(int  horz, int vert);

Як і в FlowLayout другий конструктор задає відстані між компонентами. Для того ж щоб задати вирівнювання компонентів потрібно скористатися методом add класу Container.

void add (Component compObj, Object region);

Тут compObj – компонент, що додається. region – область розсташування компонента.

При додаванні графічних елементів безпосередньо на контейнер призводить до того, що вони одержують максимальний розмір.

 
Результат виконання BorderLayoutExample1.java
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;

public class BorderLayoutExample1 {
    public static void main(String[] args) {
     ProgFrame frame = new ProgFrame();
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}

class ProgFrame extends JFrame{
    ProgFrame(){
        setSize(300,300);
        setLocation(200,200);
        //  setLayout(new BorderLayout());  по замовчуванню для JFrame
        add (new JButton ("North"), BorderLayout.NORTH);
        add (new JButton ("South"), BorderLayout.SOUTH);
        add (new JButton ("East"), BorderLayout.EAST);
        add (new JButton ("West"), BorderLayout.WEST);
        add (new JButton ("Center"), BorderLayout.CENTER);

    }
}

Результат виконання:


Як бачимо кнопки були спотворені при заповненні простору. Уникнути такого можна попередньо додавши у відповідні позиції панелі JPanel на яких і розміщувати компоненти (кнопки в даному випадку).

 
Результат виконання BorderLayoutExample2.java
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class BorderLayoutExample2 {
    public static void main(String[] args) {
     ProgFrame2 frame = new ProgFrame2();
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}

class ProgFrame2 extends JFrame{
    ProgFrame2(){
        setSize(250,200);
        setLocation(200,200);
        setLayout(new BorderLayout()); // в даному випадку необов'язково
        JPanel p= new JPanel();
        p.add (new JButton ("North"));
        add (p, BorderLayout.NORTH);
        p=new JPanel();
        p.add(new JButton ("South"));
        add (p, BorderLayout.SOUTH);
        p=new JPanel();
        p.add(new JButton ("East"));
        add (p, BorderLayout.EAST);      
        p=new JPanel();
        p.add(new JButton ("West"));
        add (p, BorderLayout.WEST);
        p=new JPanel();
        p.add(new JButton ("Center"));
        add (p, BorderLayout.CENTER);
    }
}

Як бачимо у кожен сектор ми додаємо панель, а вже на ній розміщуємо кнопку.

Зверніть увагу, що кнопки розташовані по центру зверху. Це тому, що у панелі по замовчуванню діє менеджер розташування FlowLayout. Кожній панелі можна призначити іншого менеджера. Таким чином можна розробляти більш складніший інтерфейс на основі простих менеджерів FlowLayout та BorderLayout.

GridLayout

ред.

Менеджер розташування GridLayout розташовує компоненти по рядкам і стовпцям, подібно як в електронних таблицях. Проте при цьому всі комірки однакового розміру. Компоненти автоматично будуть приведені до розміру комірок, їхні попередні розміри будуть проігноровані. При зміні розміру вікна, компоненти будуть змінюватися пропорційно.

GridLayout отримує кількість рядків та стовпців у своєму конструкторі.

panel.setLayout (new GridLayout(5,4));

Можна також вказати відстань між компонентами по горизонталі та вертикалі.

panel.setLayout(new GridLayout(5,4,3,3));

Відстані між компонентами задаються в пікселях. Самі ж компоненти додаються порядково, спочатку перший компонент першого рядка, згодом другий компонент першого рядка і т.д.

panel.add(new JButton (1));
panel.add(new JButton (2));

Наступний код виводить на екран вікно з 15-ма кнопками з використанням GridLayout.

 
GridLayoutExample.java
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Panel;
import javax.swing.JButton;
import javax.swing.JFrame;

public class GridLayoutExample {
    public static void main(String[] args) {
     Frame15 frame = new Frame15();
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}
class Frame15 extends JFrame{
    Frame15(){
        int k=0;
        Panel p=new Panel();
        setSize(300,250);
        p.setLayout(new GridLayout(4,4));
           
        for (int i=0;i<15;i++){
            k=i+1;
            JButton button=new JButton(""+k);
            button.setFont(new Font("SansSerif", Font.BOLD, 20));
            p.add (button);
            
        }
        add(p);
    }
}

Наведений приклад може бути використаний для реалізації гри в п’ятнадцять. Також GridLayout корисний для реалізації інтерфейсу калькулятора. В багатьох книжках програмування на Джава наведені приклади реалізації простого калькулятора з використанням даного менеджера.

На практиці GridLayout не дуже часто використовується. Він може бути використаний для поділу вікна на кілька рівних частин. Зокрема, якщо вказати GridLayout(1,0) – ми отримуємо один рядок і необмежену кількість стовпчиків, аналогічно GridLayout(2,0) – два рядки і необмежена кількість стовпчиків. Можна також вказувати навпаки кількість стовпчиків і тоді буде необмеженою кількість рядків. Даний менеджер розташування зручний для реалізації панелей інструментів, де кнопки мають бути однакового розміру.

BoxLayout

ред.

Менеджер BoxLayout розташовує компоненти в один рядок або стовпець. Він корисний для створення панелей інструментів, або вертикальної панелі кнопок.

BoxLayout можна застосовувати напряму як інші менеджери. У Swing також існує доволі зручний cпеціальний для цієї мети контейнер Box, який використовує BoxLayout і надає ряд корисних методів. По суті Box – це панель, для якої вже налаштоване блокове розміщення. Створюється така панель не конструктором, а одним з двох статичних методів, що визначені в класі Box: createHorizontalBox() та createVerticalBox().

Компоненти, що додаються на панель з блоковим розташуванням, вишиковуються один за іншим. Відстань між компонентами по замовчуванню нульова. Проте між ними можна додавати невидиму «розпірку» (strut), призначення якої - розсувати сусідні компоненти на потрібну відстань. Горизонтальна розпірка створюється статичним методом createHorizontalStrut (int width), а вертикальна – методом createVerticalStrut (int height).

Крім розпірок між компонентами можна вставляти так звані склейки (glue). Якщо поставити склейки між двома компонентами, то вони розсунуть їх на максимально можливу відстань, зайнявши весь вільний простір у контейнері. Якщо вставити склейки в різних місцях, то вільний простір розподілиться між компонентами де вони застосовані. Горизонтальні та вертикальні склейки створюються відповідними методами: createHorizontalGlue() і createVerticalGlue().

Наступний приклад демонструє використання об’єкту Box, розпірки та склейки.

 
BoxLayoutExample.java
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;

public class BoxLayoutExample {
    public static void main(String[] args)
    {

     PFrame frame = new PFrame();
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}

class PFrame extends JFrame{
    PFrame(){
        setTitle("Box Layout Example");
        setSize(200, 400);

        Box box = Box.createVerticalBox();
        box.add(new JButton("Кнопка 1"));
        box.add(Box.createVerticalStrut(20));
        box.add(new JButton("Кнопка 2"));
        box.add(Box.createVerticalGlue());
        box.add(new JButton("Кнопка 3"));
        box.add(Box.createVerticalGlue());
        box.add(new JButton("Кнопка 4"));
        box.add(new JButton("Кнопка 5"));

        add(box);
  
    }    
}


Як бачимо склейки використані між кнопками 2-3 та 3-4. Простір розподілено порівну. Між 1 та 2 стоїть розпірка, а між 4-5 немає нічого.

 
Кнопка Х вирівняна вправо до лінії вирівнювання

В даному прикладі усі кнопки вирівняні зліва вікна. Це вирівнювання по замовчуванню. Для цього можна скористатися методами класу JComponent setAlignmentX(float alignment), setAlignmentY(float alignment) та константами даного класу: LEFT_ALIGNMENT (по лівому краю), RIGHT_ALIGNMENT (по правому краю), CENTER_ALIGNMENT (по центру). Для вирівнюванню по вертикалі — BOTTOM_ALIGNMENT (по нижньому краю), TOP_ALIGNMENT (по верхньому краю) і CENTER_ALIGNMENT (по центру).

JButton rightButton = new JButton("Кнопка Х"); 
rightButton.setAlignmentX(JComponent.RIGHT_ALIGNMENT); 
box.add(rightButton);

Проте коли ви спробуєте надавати кожному компоненту окреме від інших вирівнювання, Ви не отримаєте потрібного результату. Причиною є те, що вирівнювання відбувається не по краях вікна, а по невидимій лінії вирівнюванню. Так якщо ви вирівнюєте по праву сторону кнопку, то лінія буде справа, а всі інші елементи зліва цієї лінії. Так наведений нижче рисунок показує результат дещо модифікованої програми, де додані вище наведені рядки.

Якщо кожній кнопці по окремості задати одне й те ж вирівнювання, то усе відображатиметься так як треба.

CardLayout

ред.

CardLayout – спеціальний менеджер розташування для створення ефекту колоди карт (стеку карт). Він дає змогу показувати одночасно лише один компонент чи контейнер з компонентами, а інші компоненти чи контейнери приховувати до певної пори. За допомогою них зручно створювати вікна з вкладками (в java вкладки реалізовуються за допомогою уже готового компонента JTabbedPane).

Щоб додавати компонент до CardLayout, використовується двох-аргументна версія методу контейнерів add. Додатковий аргументи – це довільний рядок, назва карти:

add (myComponent, "netconfigscreen");

Щоб поставити певну карту на вершину стеку, викликається метод show() класу CardLayout з двома аргументами: батьківський контейнер та назва карти, яку необхідно показати. В класі також існують методи: first(), last(), next() та previous() для роботи з стеком карт. Це нестатичні методи, тож вам потрібно створити екземпляр даного класу, щоб викликати їх.

Карти зазвичай містяться в об'єкті типу JPanel. Кожна карта також містить панель, на якій розміщені всі інші елементи.

Наступний приклад демонструє програму міні-діалог. Вікно застосунка ділиться на дві рівні вертикально розміщених частини за допомогою менеджера GridLayout. В першу частину вставляється колода карт, а в другу частину кнопка, яка дозволятиме нам міняти карту.

 
Вигляд вікна при запуску
 
Вигляд вікна після натиснення кнопки
import java.awt.CardLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class CardLayoutExample extends JPanel {
  public static void main(String[] args)
    {

     CardFrame frame = new CardFrame();
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}

class CardFrame extends JFrame{
   JPanel panel1=new JPanel();
   JPanel panel2=new JPanel();
   CardLayout cards=new CardLayout();
   JPanel cardPanel;

   CardFrame(){
        setTitle("Card Layout");
        setSize(250, 150);
   
        //додаємо у вікно панель
        JPanel p=new JPanel();
        add(p);
        // ділимо панель на дві частини за допомогою менеджера GridLayout
        p.setLayout(new GridLayout (2,1));


        cardPanel = new JPanel(); // створюємо панель для стеку карт
        cardPanel.setLayout(cards); // встановлюємо для панелі менеджер карт

        //Створюємо мітки з текстом
        //і додаємо їх до панелей
        JLabel label=new JLabel("Привіт!");
        panel1.add(label);

        JLabel label2=new JLabel("Дякую добре! Я радий тебе бачити!");
        panel2.add(label2);

        //додаємо панелі до панелі стеку карт
        cardPanel.add(panel1, "Hello");
        cardPanel.add(panel2, "Glad");
        
        //додаємо панель стеку карт у першу комірку вікна
        p.add(cardPanel);
        cards.show(cardPanel, "Hello");

        // створюємо і додаємо кнопку "Сказати привіт" у другу комірку
        JButton button=new JButton("Сказати: \"Привіт! як справи?\""); 
        p.add(button);
        
        //додаємо обробник подій, для його створення
        // використано анонімний внутрішній клас
        ActionListener listener = new ActionListener( ) {
            public void actionPerformed(ActionEvent e) {
            cards.next(cardPanel);
            }
        };
        button.addActionListener(listener);      
    }
}

Думаю з коментарів усе зрозуміло. Якщо поекспериментувати та використати, наприклад, замість кнопки випадаюче меню, то з даного застосунку можна зробити непогану гру-діалог з комп’ютером.

GridBagLayout

ред.

GridBagLayout – доволі гнучкий менеджер розташування, що дозволяє розміщувати компоненти відносно інших, використовуючи обмеження. З GridBagLayout можна створити також будь-який уявний менеджер розташування. Компоненти розташовуються по логічних координатах на уявній решітці. Рядки і стовпчики можуть мати різноманітний розмір, який залежить від розміру компонент, які вони містять. Сам процес розбиття на рядки і стовпчики дещо нагадує створення таблиць в HTML.

Використання GridBagLayout дещо складніше ніж інших менеджерів, оскільки потребує деяких практичних навичок і вміння встановлювати обмеження. Проте після того як Ви зрозумієте основні правила роботи з менеджером, його застосування не складатиме для Вас проблеми.

Розміщення та розміри кожного компонента в решітці визначається набором обмежень, пов’язаних з ним. Обмеження містяться в об’єкті типу GridBagConstraints. Обмеження включають висоту і ширину комірки, розміщення компоненти, її вирівнювання і току зв’язування в середині комірки.

Загальна процедура використання решітчастого розміщення виглядає так. Спочатку створюється новий об’єкт GridBagLayout, який призначається поточним диспетчером розташування. Далі вказуються обмеження для кожного компонента, що додається в решітку. Після всього цього компонент додається до диспетчера. Тобто необхідно здійснити наступні кроки:

  1. Створити об’єкт GridBagLayout. При цьому конструктор не знає, скільки рядків і стовпців містить решітка. Пізніше об’єкт сам спробує вгадати ці параметри по інформації, яку одержить з програми.
  2. Зв’язуємо об’єкт GridBagLayout з контейнером.
  3. Для кожного компонента створити об’єкт GridBagConstraints. Цей об’єкт буде задавати розміщення компонент.
  4. Додати компонент та його обмеженням за допомогою наступної інструкції:

add (Component, constraints)

Також можна використати метод setConstraints (component, constraints); класу GridBagLayout.

Як бачимо головною задачею є задання обмежень для кожної компоненти. Тому розглянемо детальніше клас GridBagConstraints.

Клас GridBagConstraints

ред.

Клас GridBagConstraints доволі простий. Він має лише один конструктор без аргументів. Обмеження для компонент задаються у полях класу. Розглянемо їх поки що в загальному:

Поле Призначення
int gridx, gridy Контролюють місцезнаходження компонент на решітці розміщення:
double weightx, weighty Контролюють як розподіляється додатковий простір між краями контейнера (наприклад, вікном) і комірками решітки (по замовчуванню 0,0 – простір рівномірно розміститься по краях контейнера). Чим більша вага тим більшим буде проміжок.
int fill Контролює як компоненти підлаштовуються під розмір комірки (чи заповнюють усе чи ні)
int gridheight, gridwidth Контролює скільки рядків або стовпців займає компонент (по замовчуванню 1)
int anchor Прив’язує компонент до певної позиції в середині комірки (центр, північ, схід і т.п.)
int ipadx, ipady Контролює простір між компонентом та межами комірки (по замовчуванню 0)
Insets insets Задає вставки, тобто простір між компонентою та сусідньою компонентою

Як вже було сказано найлегшим способом розміщення компоненти і встановлення обмежень для неї є використання методу add():

Container content = getContentPane( );
JComponent component = new JLabel("constrain me, please...");
GridBagConstraints constraints = new GridBagConstraints( );
constraints.gridx = x;
constraints.gridy = y;
...
content.add(component, constraints);

Можна також додати компонент в контейнер звичайним методом add(component), а далі, щоб зв’язати з ним відповідні обмеження використати метод setConsraints():

add(component);
...
myGridBagLayout.setConstraints(component, constraints);

Загалом для компонент приходиться задавати одні і ті ж обмеження, тому логічним є створення набору об’єктів GridBagConstraints і зв’язувати конкретний об’єкт з компонентом.

Координати

ред.

Координати в GridBagLayout не задаються з самого початку. Розмір решітки може змінюватися в залежності від кількості компонентів і встановлених для них параметрів gridx та gridy. Так, якщо ви помістите компонент і задасте цим параметрам значення 25, то буде створена решітка 25х25. Якщо ви додасте інший компонент з gridx=30 gridy=14, то розмір решітки зміниться до 30х25. Менеджер автоматично встановлює необхідні розміри решітки при додаванні компонентів.

Наступний приклад демонструє використання gridx та gridy при розміщенні компонентів.

 
GridBagLayoutExample.java
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class GridBagLayoutExample {
    public static void main(String[] args) {
     GrFrame frame = new GrFrame();
     frame.setSize(250, 200);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}  
    
class GrFrame extends JFrame{
    GridBagConstraints constraints = new GridBagConstraints();
        
        
    GrFrame(){
        setLayout (new GridBagLayout());
        int x,y;
        
        setGrid(new JButton ("1, 0"), x=1, y=0);
        setGrid(new JButton ("0, 1"), 0, 1);
        setGrid(new JButton ("1, 1"), 1, 1);
        setGrid(new JButton ("2, 1"), 2, 1);
        setGrid(new JButton ("1, 2"), 1, 2);
        
    }   
    void setGrid (Component component, int x, int y){
        constraints.gridx=x;
        constraints.gridy=y;
        add (component, constraints);
    }
}

В даному прикладі компоненти знаходяться в центрі, впритул один до одного. Весь вільний простір розташований по боках вікна. Щоб простір розподілився між комірками з компонентами необхідно задати ваги (weightx, weighty), а щоб кнопки зайняли усе місце в комірці необхідно задати поле заповнення (fill).

Обмеження заповнення (fill)

ред.

Задамо, щоб кнопки зайняли рівномірно максимально можливий простір вікна. Для цього необхідно задати обмеження fill та встановити weihtx, weighty у ненульові значення.

 
GridBagLayoutEx2.java
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class GridBagLayoutEx2 {
    public static void main(String[] args) {
     GridFrame frame = new GridFrame();
     frame.setSize(250, 200);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}  
    
class GridFrame extends JFrame{
    GridBagConstraints constraints = new GridBagConstraints();
        
        
    GridFrame(){
        setLayout (new GridBagLayout());
        int x,y;
        
        constraints.fill=GridBagConstraints.BOTH;
        constraints.weightx=1.0;
        constraints.weighty=1.0;
     
        setInGrid(new JButton ("1, 0"), x=1, y=0);
        setInGrid(new JButton ("0, 1"), 0, 1);
        setInGrid(new JButton ("1, 1"), 1, 1);
        setInGrid(new JButton ("2, 1"), 2, 1);
        setInGrid(new JButton ("1, 2"), 1, 2);
        
    }   
    private void  setInGrid (Component component, int x, int y){
        constraints.gridx=x;
        constraints.gridy=y;
        add (component, constraints);
    }
}

BOTH – одна з констант классу GridBagConstraints. Вона вказує, що компонент повинен заповнювати простір в обох напрямках (вертикально та горизонтально). Доступні наступні константи:

HORIZONTAL – заповнення доступного горизонтального простору

VERTICAL – заповнення доступного вертикального простору

BOTH – заповнення доступного простору в обох напрямках

NONE – не заповнювати доступний простір; зображати компоненти в їхньому бажаному розмірі

Об’єднання рядків та стовпців

ред.

GridBagLayout дозволяє задавати, що компонент займатиме більше одного рядка або стовпця. Об’єднання (span) відбувається дещо подібно до html. Для цього використовуються дві змінні gridheight та gridwidth класу GridBagConsrtaints. Наступний приклад демонструє. Охоплення кнопкою двох рядків вертикально та іншою кнопкою двох стовпців горизонтально.

 
GridBagLayoutEx3.java
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;


public class GridBagLayoutEx3 {
    public static void main(String[] args) {
     GridFrame2 frame = new GridFrame2();
     frame.setSize(250, 200);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}  
    
class GridFrame2 extends JFrame{
    GridBagConstraints constraints = new GridBagConstraints();
        
        
    GridFrame2(){
        setLayout (new GridBagLayout());
        int x,y;
        
        
        constraints.fill=GridBagConstraints.BOTH;
        constraints.weightx=1.0;
        constraints.weighty=1.0;
     
        
        constraints.gridheight=2; // об'єднати два рядки
        setInGrid(new JButton ("0, 0"), x=0, y=0);
       // setInGrid(new JButton ("0, 1"), 0, 1); // дана комірка тепер буде зайнята кнопкою (0,0)
        constraints.gridheight=1; // повернутись до попередьного значення
        setInGrid(new JButton ("1, 0"), 1, 0);
        setInGrid(new JButton ("2, 0"), 2, 0);
        constraints.gridwidth=2;
        setInGrid(new JButton ("1, 1"), 1, 1);
        constraints.gridheight=1;
    }   
    private void  setInGrid (Component component, int x, int y){
        constraints.gridx=x;
        constraints.gridy=y;
        add (component, constraints);
    }
}

Як бачимо перша кнопка тепер займає комірки (0,0) та (0,1) Кнопка «1,1» займає комірки з координатами (1,1) та (1,2). Якщо Ви спробуєте розмістити за даними позиціями компоненти, то відображення компонент може бути не передбачуватиме, тому потрібно добре розраховувати де ви розміщуєте компоненти. Лишнє мабуть говорити, що замість кнопок ви можете вставляти контейнери і уже в контейнерах застосовувати інші менеджери розташування. Таким чином ви можете створювати довільного виду графічний інтерфейс.

Зважування

ред.

Поля weightx та weighty класу GridBagConstraints визначають як додатковий простір в контейнері розподіляється між рядками і стовпчиками. Чим більше значення змінної тим більше простору одержить компонент, менше значення – значить він займатиме менше простору. При чому власне значення не мають значення, а лише їхні співвідношення між собою. Це все при умові, що задіяна змінна fill. Інакше простір займає комірка в якому міститься компонент, а компонент займає бажаний для нього розмір.

Наступний приклад демонструє вище сказане:

 
GridBagLayoutEx4.java
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;


public class GridBagLayoutEx4 {
    public static void main(String[] args) {
     GridFrame3 frame = new GridFrame3();
     frame.setSize(500, 100);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}  
    
class GridFrame3 extends JFrame{
    GridBagConstraints constraints = new GridBagConstraints();
        
        
    GridFrame3(){
        setLayout (new GridBagLayout());
        int x,y;
        
        constraints.fill=GridBagConstraints.BOTH;
        constraints.weightx=0.1;
        constraints.weighty=1.0;
        
           
        setInGrid(new JButton ("Один"), x=0, y=0);
        constraints.weightx=0.5;
        setInGrid(new JButton ("Два"), 1, 0);
        constraints.weightx=0.3;
        setInGrid(new JButton ("Три"), 2, 0);
        
        
        
    }   
    private void  setInGrid (Component component, int x, int y){
        constraints.gridx=x;
        constraints.gridy=y;
        add (component, constraints);
    }
}


Як бачимо під кожну кнопку відведено простір відносно значень weightx. Найбільше отримала друга кнопка, оскільки значення змінної для неї найбільше. Ви можете легко розподілити простір для кожної компоненти.

Якщо у вас присутні кілька рядків, то при розподіленні враховується найбільша вага компоненти в стовпчику.

Anchor (якір)

ред.

Якщо елемент менший за простір наданий йому, він центрується за замовчуванням. Проте центр не єдине можливе розміщення. Змінна anchor (чит. як енке – якір) дозволяє задати позиціювання компонента в комірці. Можливими значеннями є: GridBagConstraints.CENTER, NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST та NORTHWEST. Наприклад, якір GridBagConstraints.NORTH – відцентрує компонент зверху, SOUTHEAST – розміщує його у нижньому-правому куті площини.

Набивка (padding) і вставки (insets)

ред.
 
Набивка і вставки

Іншим шляхом контролювати поведінку компонент в менеджері GridBagLayout є використання набивки (padding) та вставок(insets). Набивка визначається полями ipadx і ipady классу GridBagConstraints. Вони визначають горизонтальний і вертикальний «ріст» компонента. На рисунку зображено місця набивки і вставки.

Таким чином можна задавати довільні розміри компонента та більш краще його розміщення всередині певного контейнера.

Відносне позиціонування

ред.

В наведених вище прикладах, при використанні GridBagLayout ми задавали координати gridx та gridy кожного компонента явно задаючи обмеження. Альтернативним способом є відносне розміщення. При ньому ми просто вказуємо помістити компонент зліва чи знизу попереднього компонента. Щоб зробити це потрібно присвоїти gridx або gridy значення константи GridBagConstraints.RELATIVE. При цьому потрібно враховувати:

  • Щоб встановити компонент справа попереднього, необхідно встановити gridx як RELATIVE і використати теж саме значення gridy, яке було використане для попереднього компонента.
  • відповідно, щоб встановити компонент знизу попереднього, встановіть gridy в RELATIVE та залиште gridx незмінним.
  • якщо встановити обидва поля gridx та gridy в RELATIVE, то компоненти будуть розміщені в один в рядок, а не по діагоналі як можна б було очікувати.

Відносне розміщення корисне при розсташуванні компонентів в ряд або в стовпчик.

Нестандартні менеджери розташування

ред.

Тут наведені основні менеджери розташування, за допомогою їхнього поєднання можна зробити практично будь-який інтерфейс. Проте це не всі менеджери. Існують і інші менеджери, які розроблені як розробниками java так і сторонніми розробниками. Щоправда немає ніякої гарантії, що вони будуть доступні на всіх ОС платформах і що їхні нові версії будуть сумісними з попередніми. Зокрема, можете звернутися до пакету класів sun.awt та заглянути на www.gamelan.com.

Абсолютне позиціонування

ред.

Існує можливість усунути менеджер розташування. Після чого можна розміщувати об’єкти на екрані використовуючи абсолютні координати. Це загалом не дуже зручний підхід. Компоненти можуть мати різноманітний мінімальний розмір на різних платформах і інтерфейс може бути не переносимим.

Наступний приклад демонструє використання абсолютного позиціонування.

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class AbsPositioning {
   public static void main(String[] args) {
     PosFrame frame = new PosFrame();
     frame.setSize(300, 250);
     frame.setLocation(300, 200);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    } 
}

//Створюємо фрейм і додаємо панель
 class PosFrame extends JFrame{
      PosFrame(){
      PosPanel panel = new PosPanel();
      add(panel);
    }
 }   
 //панель з кнопкою, що рухається
 class PosPanel extends JPanel{
      JButton button = new JButton("Я рухаюсь");
      
      PosPanel(){  
      setLayout(null);//не застосовувати менеджер розташування    
      add(button);
      button.setSize(button.getPreferredSize());
      button.setLocation(10, 20);
      //обробка клацання мишею
      addMouseListener(new MouseAdapter(){
        @Override
        public void mousePressed (MouseEvent e){
            button.setLocation(e.getX(), e.getY());
        }
        });  
      }
  }

Як бачимо програма промальовує кнопку і при натисканні на будь-яку кнопку миші кнопка переміщується в місце клацання. При зміні розміру вікна, місце розташування залишатиметься незмінне відносно верхнього лівого кута.

Графічний інтерфейс користувача · Графічні компоненти Swing