Шаг 6 - Работа с Layout Manager

Загрузить проект

Немного теории

В Java нельзя размещать компоненты в окнах с точно задаными координатами. Что значит нельзя? Технически это возможно и в ряде случаев даже имеет смысл. Например если вы пишете приложение для одной ОС и кросплатформенность его вас не интересует. Но в общем случае вы не можете знать под чем и на каком железе будет исполняться ваше приложение и поэтому не можете размещать компоненты указав точные координаты, а для апплетов это вообще крайне нежелательно. В то же время система Layout Manager способна динамически вибирать размеры компонент и размещать их при различных условиях работы. Это дает некоторую уверенность в том что вашы компоненты на экране пользователя независимо от его железа, размера системного шрифта и др. будут размещены так как вы это планировали. Еще один аргумент: кто програмировал под Win знает какие проблемы возникают с диалоговымы окнами при изменении их размеров (если такое не запретить) - надо обработать сообщение, переместить компоненты на новые места и т.д. В принцыпе система Layout Manager избавляет от этих забот.

При работе с Layout Manager вы выбираете один из его режимов размещения компонет, устанавливаете его для своей панели (окна апплета, приложения) и далее добавляете в панель компоненты используя разновидность метода add для этого режима. Перечислим основные режимы:

Думаю, что комбинируя вышеперечисленные режимы и возможности JPanel можно разместить компоненты любым образом.

Сегодня напишем приложение с использованием JFC/Swing (неконсольное конечно). Для этого унаследуем свой главный класс от класса JFrame. Вот его родословная:

java.lang.Object -> java.awt.Component -> java.awt.Container -> java.awt.Window -> java.awt.Frame -> javax.swing.JFrame

С первыми тремя объектами мы уже знакомы. Класс Window представляет собой окно без меню и рамки и содержит основные методы для работы с окнами. Главная его роль быть базовым для более используемых окон Frame, Dialog и др. Его потомок Frame служит для создания окон которые имеют строку названия, рамку, могут иметь меню. Класс JFrame Swing-аналог своего AWT-родителя.

В нижеприведенном примере мы разместим в окне главного приложения 6 панелей одну под одной, установив для каждой свой режим размещения компонент, и добавим в каждую панель несколько кнопок (в одной из панелей обойдемся без Layout Manager задав компонентам конкретные координаты и посмотрим что из этого выйдет). Посколько кнопок нам понадобиться много создадим их целый массив. Для этого разберемся как создаются в Java массивы.

Массивы в Java являются объектами специального встроенного класса. Для их создания используют оператор []. Чтобы определить размер массива этот клаас содержит поле length.
Пример создания одномерного массива объектов:

AnyObject[] matrixOfAnyObj; //обьявляем массив matrixOfAnyObj
matrixOfAnyObj=new AnyObject[5]; //создаем массив размером в 5 элементов
//создадим объекты - элементы массива в цыкле
//индекс первого элемента массива == 0
for (int i=0; i<5; i++) matrixOfAnyObj[i]=new AnyObject();

Можно создать массив и без оператора new проинициализировав его. Пример:

String[] = {"строка 1", "вторая строка", "третья", "и т.д."};

Многомерные массивы создаются как массивы массивов. Например чтоб создать трехмерный массив создаем его как массив двумерных массивов а те в свою очередь являются массивами одномерных массивов. Каламбуры какие-то получаются, лучше посмотрим пример создания трехмерного массива:

int[][][] NumMatrix=new int[2][3][4]; //обьявим и создадим трехмерный массив
NumMatrix[0]=new int[3][4]; //создаем соответствующие двумерные массивы
NumMatrix[1]=new int[3][4]; //их размер может быть неидентичным
//но я выбрал одинаковый размер чтоб создать одномерные массивы в цыкле, сделаем это:
for(int i=0; i<2;i++)
{
 for(int j=0; j<3; j++)
 {
  NumMatrix[i][j] = new int [4];
 }
}

К сказанному пожалуй нужно добавить что в Java происходит контроль выхода за границы массива и если что то не так - создается исключение.

Создаем код

import java.awt.*;
import javax.swing.*;
public class LayoutApplication extends JFrame
{
   //Обьявляем массивы кнопок и панелей
 JButton[] ArrOfButton;
 JPanel[] ArrOfPanel;
 
 
 public LayoutApplication()
 {
    //позволим конструктору предка выполнить всю черновую работу
    //по созданию окна с нашим заголовком
  super("OurApplication");
  
    //создем массивы
  ArrOfButton=new JButton[25];
  ArrOfPanel=new JPanel[6];
  
    //создаем кнопки и панели как элементы масивов 
  for (int i=0; i<25;i++)
  {
   ArrOfButton[i]=new JButton("Butt No "+String.valueOf(i+1));
  }
  for (int i=0; i<6;i++)
  {
   ArrOfPanel[i]=new JPanel();
  }
  
    //получаем из нашего окна панель которая будет размещать компоненты
    //и установим для нее GridLayout, при его создании задаем в параметрах
    //6 строк 1 столбец и зазор 5 пикселей
    //в эту панел мы будем добавлять панели с кнопками
  Container ContPane=getContentPane();
  ContPane.setLayout(new GridLayout(6,1,5,5));

/////////////
    //для первой панели зададим FlowLayout (хоть он там и по умолчанию 
    //стоит:)) о окружим эту панель черной рамкой, чтоб отличать панели
    //я решил им рамки разноцветные сделать. 
    //После чего додадим в цыкле пару кнопок
  ArrOfPanel[0].setLayout(new FlowLayout());
  ArrOfPanel[0].setBorder(BorderFactory.createLineBorder(Color.black));
  for (int i=0; i<5;i++)
  {
   ArrOfPanel[0].add(ArrOfButton[i]);
  }

///////////////////////////////
    //У этой панели будет BorderLayout и красная рамка
    //обратите внимание на функцию add
  ArrOfPanel[1].setLayout(new BorderLayout());
  ArrOfPanel[1].setBorder(BorderFactory.createLineBorder(Color.red));
  

  ArrOfPanel[1].add(BorderLayout.NORTH, ArrOfButton[5]);
  ArrOfPanel[1].add(BorderLayout.SOUTH, ArrOfButton[6]);
  ArrOfPanel[1].add(BorderLayout.WEST, ArrOfButton[7]);
  ArrOfPanel[1].add(BorderLayout.EAST, ArrOfButton[8]);
  ArrOfPanel[1].add(BorderLayout.CENTER, ArrOfButton[9]);

////////////////////////////////
    //здесь GridLayout с тремя строками и двумя колонками
  ArrOfPanel[2].setLayout(new GridLayout(3,2));
  ArrOfPanel[2].setBorder(BorderFactory.createLineBorder(Color.green));

  for (int i=10; i<15;i++)
  {
   ArrOfPanel[2].add(ArrOfButton[i]);
  }

///////////////////////////////
    //а здесь не будем использовать никакого Layout
    //функцией setBounds задаем координаты верхнего левого края компоненты
    //и ширину с высотой
  ArrOfPanel[3].setLayout(null);
  ArrOfPanel[3].setBorder(BorderFactory.createLineBorder(Color.blue));

  for (int i=15; i<18;i++)
  {
   ArrOfPanel[3].add(ArrOfButton[i]);
   ArrOfButton[i].setBounds(140*(i-15)+5,5*(i-15)+5,135,20);
  }

//////////////////////////
    //здесь самый козырный GridBagLayout - я разместил здесь компоненты 
    //по квазидиагонали как в предыдещей панели
    //перед использованием метода add мы здесь сначала заполняем поля класса
    //GridBagConstraints и с помощью функции setConstraints асоциируем с
    //каждым компонентом свои данные
  GridBagLayout gridbag=new GridBagLayout();
  ArrOfPanel[4].setLayout(gridbag);
  ArrOfPanel[4].setBorder(BorderFactory.createLineBorder(Color.yellow));

  GridBagConstraints GrBgCnstr = new GridBagConstraints();
  
  GrBgCnstr.fill = GridBagConstraints.BOTH;
  
  GrBgCnstr.gridx = 0;
  GrBgCnstr.gridy = 0;
  gridbag.setConstraints(ArrOfButton[18], GrBgCnstr);
  ArrOfPanel[4].add(ArrOfButton[18]);
  
  GrBgCnstr.gridx = 1;
  GrBgCnstr.gridy = 1;
  gridbag.setConstraints(ArrOfButton[19], GrBgCnstr);
  ArrOfPanel[4].add(ArrOfButton[19]);
  
  GrBgCnstr.gridx = 2;
  GrBgCnstr.gridy = 2;
  gridbag.setConstraints(ArrOfButton[20], GrBgCnstr);
  ArrOfPanel[4].add(ArrOfButton[20]);

///////////////////////////
    //и наконец у последней панели будет режим BoxLayout
  ArrOfPanel[5].setLayout(new BoxLayout(ArrOfPanel[5],BoxLayout.X_AXIS));
  ArrOfPanel[5].setBorder(BorderFactory.createLineBorder(Color.magenta));

  for (int i=21; i<25;i++)
  {
   ArrOfPanel[5].add(ArrOfButton[i]);
  }
  
//////////////////  
    //поместим панели с кнопками на главную панель нашего окна
  for (int i=0; i<6;i++)
  {
   ContPane.add(ArrOfPanel[i]);
  }
}

 
 public static void main(String args[])
 {
    //создадим создадим экземпляр нашего главного класса
  LayoutApplication OurAppWin = new LayoutApplication();
    //возложим обработку выхода из приложения на предка
  OurAppWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //скажем главному окну пусть реализирует себя и все свое вместимое
    //кроме прочего эта функция задаст окну приложения оптимальный размер
    //чтоб все в нем хорошо поместилось
  OurAppWin.pack();
    //покажем наше главное окно, ибо потомки класса Window 
    //(каким и является наше окно) зарождаются скрытыми
  OurAppWin.setVisible(true);
 }
}
Компилируем, запускаем. Кстати вы, наверное, подумаете: а зачем это он такой длиннющий и нечитабельный код наваял?. Отвечаю: я старался показать одновременно все режимы размещения компонент. А теперь потратьте пару минут и проанализируйте что делается в каждой отдельной панели (цветными рамками они окружены) когда вы меняете размер главного окна приложения. Сравните одно с другим! Надеюсь это поможет вам в будущем выбрать необходимый режим размещения для ваших компонент. Если у кого не получилось что - грузите проект, в нем кроме вышеописанного приложения вы найдете аналогичное приложение (с кодом конечно) под AWT - компоненты.

Далее

Обрабатываем события
Автор: Vitaly
Hosted by uCoz