Слайд 1Программирование на Java
Тема 6.1 Программирование GUI с использованием Swing
Слайд 2 AWT
Пакеты, содержащие наборы классов для создания графического
пользовательского интерфейса:
java.awt (AWT — Abstract Window Toolkit)
javax.swing
Исходная иерархия классов
AWT
Слайд 3 AWT
Исходное назначение AWT — предоставить набор графических компонентов,
который вобрал бы в себя наиболее характерные черты современных элементов
управления и позволил бы однократно создавать пользовательские интерфейсы, подходящие для любой платформы.
Компоненты AWT на самом деле не выполняли никакой работы и были очень простыми — это были просто «Java-оболочки» для элементов управления той операционной системы, на которой работала JVM и пользователь. Все запросы к этим компонентам незаметно перенаправлялись к операционной системе, которая и выполняла всю работу. Чтобы сделать классы AWT независимыми от конкретной платформы, каждому из них был сопоставлен своеобразный помощник1 (peer),ькоторый и работал с этой платформой. Для того чтобы встроить в AWT поддержку новой платформы, нужно было просто переписать код этих помощников, а интерфейс основных классов оставался неизменным.
На слайде показана исходная иерархия классов AWT. Диаграмма следует формату унифицированного языка моделирования (Unified Modeling Language, UML): сверху располагаются базовые классы, а ниже классы, унаследованные от базовых.
Базовые свойства и поведение всех графических компонентов были описаны в абстрактном классе Component, который таким образом стал ядром библиотеки AWT. Почти все компоненты пользовательского интерфейса (за исключением меню) были унаследованы от этого класса (вы можете видеть это на диаграмме наследования). Важным частным случаем компонента в AWT являлся так называемый контейнер, отличительные черты которого были описаны в классе Container (также абстрактном). Контейнер отличался от обычных компонентов тем, что мог содержать в себе другие компоненты (а значит, и другие контейнеры, что позволяло организовывать пользовательские интерфейсы любой сложности).
Слайд 4 Swing
Компоненты Swing — это легковесные компоненты AWT
Диаграмма
наследования компонентов библиотеки Swing
Слайд 5 Swing
Java — полноценный и весьма мощный язык программирования,
и для создания чего-либо на нем вовсе не обязательно обращаться
к ресурсам операционной системы. Эта простая мысль стала отправной точкой в процессе разработки легковесных компонентов.
Легковесный компонент — это просто область в пространстве экрана, занимаемом вашим Java-приложением. Главные его атрибуты — это координаты в окне и размер. Для операционной системы легковесный компонент вообще не существует, потому что представляет собой всего лишь часть какого-то окна. Всю работу по поддержке легковесных компонентов взяли на себя библиотека AWT и виртуальная машина Java. Для программиста не существует никакого отличия между легковесными и обычными компонентами, которые по аналогии стали называть тяжеловесными , то есть имеющими связь с операционной системой и представленными в своем собственном окне.
Создать легковесный компонент в AWT можно двумя способами: унаследовать класс своего компонента от абстрактного класса Component (и получить обычный легковесный компонент) или унаследовать свой компонент от уже существующего наследника класса Component, другого абстрактного класса Container (и получить контейнер, тоже легковесный). По диаграмме наследования, представленной на слайде, видно, какой путь избрали создатели Swing.
Базовый класс библиотеки Swing стал называться JComponent и был унаследован от абстрактного класса Container, определяющего поведение контейнеров AWT.
Создатели Swing постарались максимально облегчить переход от AWT к новой библиотеке, практически полностью сохранив в ней имена классов AWT и их методов. Все компоненты AWT имеют своих наследников в Swing, и имена классов этих компонентов отличаются лишь префиксом «J» (например, тяжеловесная кнопка Button имеет в Swing свой легковесный аналог — кнопку JButton).
Слайд 6 Окна Swing
Конструкторы
JFrame()
JFrame(String title)
Методы
setSize(int width, int height)
setDefaultCloseOperation(int operation)
setVisible(boolean
visible)
Слайд 7 Окна Swing
Легковесные компоненты Swing унаследованы от класса JComponent.
Для легковесных компонеттов должен иметься тяжеловесный контейнер, который будет отвечать
за прорисовку всех содержащихся в нем легковесных компонентов. В AWT такими контейнерами чаще всего служили окна Frame и Dialog, а также класс апплетов Applet. Swing предоставляет свои, слегка измененные тяжеловесные контейнеры высшего уровня: окна JWindow, JDialog и JFrame, а также апплет JApplet. Они наследуют напрямую от окон AWT.
Класс JWindow — простейшее окно, без рамки и без строки заголовка. Обычно с его помощью делается заставка к программе.
Класс JFrame, представляющий собой окно с рамкой и строкой заголовка (с кнопками «Свернуть», «Во весь экран» и «Закрыть»). Оно может изменять размеры и перемещаться по экрану.
Конструктор JFrame() без параметров создает пустое окно. Конструктор JFrame(String title) создает пустое окно с заголовком title.
Чтобы написать простейшую программу, выводящую на экран пустое окно, нам потребуется еще три метода:
setSize(int width, int height) — устанавливает размеры окна. Если не задать размеры, окно будет иметь нулевую высоту независимо от того, что в нем находится и пользователю после запуска придется растягивать окно вручную. Размеры окна включают не только «рабочую» область, но и границы и строку заголовка.
setDefaultCloseOperation(int operation) — позволяет указать действие, которое необходимо выполнить, когда пользователь закрывает окно нажатием на крестик. Обычно в программе есть одно или несколько окон при закрытии которых программа прекращает работу. Для того, чтобы запрограммировать это поведение, следует в качестве параметра operation передать константу EXIT_ON_CLOSE, описанную в классе JFrame.
setVisible(boolean visible) — когда окно создается, оно по умолчанию невидимо. Чтобы отобразить окно на экране, вызывается данный метод с параметром true. Если вызвать его с параметром false, окно снова станет невидимым.
Слайд 8 Swing
Пример . Простое окно
package prog1;
import javax.swing.*;
public class Prog1
{ public static void main (String[]
args)
{ JFrame myWindow =new JFrame("Пробное окно");
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myWindow.setSize(400, 300);
myWindow.setVisible(true);
}
}
Слайд 9 Swing
На слайде представлена программа, которая создает окно, выводит
его на экран и завершает работу после того, как пользователь
закрывает окно.
Для работы с большинством классов библиотеки Swing понадобится импортировать пакет java.swing.*
Как правило, перед отображением окна, необходимо совершить гораздо больше действий, чем в этой простой программе. Необходимо создать множество элементов управления, настроить их внешний вид, разместить в нужных местах окна. Кроме того, в программе может быть много окон и настраивать их все в методе main() неудобно и неправильно, поскольку нарушает принцип инкапсуляции: держать вместе данные и команды, которые их обрабатывают. Логичнее было бы, чтобы каждое окно занималось своими размерами и содержимым самостоятельно.
Классическая структура программы с окнами представлена на следующем слайде.
Слайд 10 Swing
Пример . Классическая структура программы с окнами
// В файле SimpleWindow.java:
package progr2;
import javax.swing.*;
class SimpleWindow
extends JFrame
{ SimpleWindow(){ super("Пробное окно");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(250, 100);
JButton newButton = new JButton("Кнопка");
getContentPane().add(newButton);
}
}
// В файле Progr2.java:
package progr2;
import javax.swing.*;
public class Progr2
{ public static void main (String[] args)
{ JFrame myWindow =new SimpleWindow();
myWindow.setVisible(true);
}
}
Слайд 11 Swing
Из примера видно, что окно описывается в отдельном
классе, являющемся наследником JFrame и настраивающее свой внешний вид и поведение в
конструкторе (первой командой вызывается конструктор суперкласса).
Метод main()содержится в другом классе, ответственном за управление ходом программы. Каждый из этих классов очень прост, каждый занимается своим делом, поэтому в них легко разбираться и легко сопровождать (т.е. совершенствовать при необходимости).
Обратите внимание, что метод setVisible() не вызывается в классе SimpleWindow, что вполне логично: за тем, где какая кнопка расположена и какие размеры оно должно иметь, следит само окно, а вот принимать решение о том, какое окно в какой момент выводится на экран — прерогатива управляющего класса программы.
Напрямую в окне элементы управления не размещаются. Для этого служит панель содержимого, занимающая все пространство окна. Обратиться к этой панели можно методом getContentPane() класса JFrame. С помощью метода add(Component component) можно добавить на нее любой элемент управления. В примере в панель содержимого нашего окна добавлена кнопка. Кнопка описывается классом JButton и создается конструктором с параметром типа String — надписью.
Кнопка занимает всю доступную площадь окна. Такой эффект полезен не во всех программах, поэтому необходимо изучить различные способы расположения элементов на панели.
Слайд 12 Swing
Класс Container (контейнер)
Методы
add(Component component) // добавляет в контейнер
эл-т
remove(Component component) // удаляет из контейнера эл-т
removeAll() // удаляет все элементы контейнера;
getComponentCount() //
возвращает число элементов
// контейнера.
getComponentAt(int x, int y)
Класс JPanel (панель)
setLayout(LayoutManager manager) // изменяет менеджер
// размещения
Слайд 13 Swing
Элементы, которые содержат другие элементы, называются контейнерами. Все
они являются потомками класса Container и наследуют от него ряд полезных
методов:
add(Component component) — добавляет в контейнер элемент component;
remove(Component component) — удаляет из контейнера элемент component;
removeAll() — удаляет все элементы контейнера;
getComponentCount() — возвращает число элементов контейнера.
Кроме перечисленных в классе Container определено около двух десятков методов для управления набором компонентов, содержащихся в контейнере. Как видно, они похожи на методы класса-коллекции. Это неудивительно, ведь по сути контейнер и является коллекцией, но коллекцией особого рода — визуальной. Кроме хранения элементов контейнер занимается их пространственным расположением и прорисовкой. В частности, он имеет метод getComponentAt(int x, int y), возвращающий компонент, в который попадает точка с заданными координатами (координаты отсчитываются от левого верхнего угла компонента) и ряд других. Мы не будем подробно рассматривать абстрактный контейнер, а сразу перейдем к его наиболее часто используемому потомку — классу JPanel.
Панель JPanel — это элемент управления, представляющий собой прямоугольное пространство, на котором можно размещать другие элементы. Элементы добавляются и удаляются методами, унаследованными от класса Container.
В примере с кнопкой мы наблюдали, как добавленная на панель содержимого кнопка заняла все ее пространство. Это происходит не всегда. На самом деле у каждой панели есть так называемый менеджер размещения, который определяет стратегию взаимного расположения элементов, добавляемых на панель. Его можно изменить методом setLayout(LayoutManager manager). Но чтобы передать в этот метод нужный параметр, необходимо знать, какими бывают менеджеры.
Слайд 14 Swing
Менеджер последовательного размещения FlowLayout
Добавить в файл
SimpleWindow.java: import java.awt.*;
Измененный конструктор класса SimpleWindow :
SimpleWindow()
{ super("Пробное окно");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
// FlowLayout newLayout = new FlowLayout();
// panel.setLayout(newLayout);
panel.add(new JButton("Кнопка"));
panel.add(new JButton("+"));
panel.add(new JButton("-"));
panel.add(new JButton("Кнопка с длинной надписью"));
setContentPane(panel);
setSize(250, 100);
}
Слайд 15 Swing
Самый простой менеджер размещения — FlowLayout. Он размещает добавляемые
на панель компоненты строго по очереди, строка за строкой, в
зависимости от размеров панели. Как только очередной элемент не помещается в текущей строке, он переносится на следующую.
Лучше всего пронаблюдать это на примере. На слайде представлен измененный конструктор класса SimpleWindow .
Менеджеры расположения описаны в пакете java.awt. Не забывайте импортировать нужные классы.
Пронаблюдайте за поведением окна, появляющегося после запуска программы. Четыре кнопки в нем расположены как слова в текстовом редакторе (при выравнивании по центру). Эффект будет лучше заметен, если изменять размеры окна во время работы программы.
Проанализируем текст примера. Новый менеджер расположения FlowLayout создается конструктором без параметров. Обратите внимание, в программе не используется промежуточная переменная. То есть вместо двух команд:
FlowLayout newLayout = new FlowLayout();
panel.setLayout(newLayout);
Мы используем одну:
panel.setLayout(new FlowLayout());
Это вполне допустимо в тех случаях, когда в дальнейшем нам не потребуется обращаться к создаваемому объекту (что справедливо для данного примера). Мы создаем менеджер расположения, тут же привязываем его к панели — и все. Теперь панель и менеджер сами найдут друг с другом общий язык.
Точно также мы добавляем на панель новые кнопки. Мы нигде больше не пытаемся обратиться к этим кнопкам в программе, поэтому заводить под них переменные нет смысла.
Метод setContentPane(JPanel panel) позволяет заменить панель содержимого окна.
Слайд 16 Swing
Замечание. Панель хранит ссылку на своего менеджера и
сама обращается к нему каждый раз, когда нужно рассчитать координаты
элементов (это происходит при их добавлении, удалении, изменении размеров, а также при изменении размеров окна).
В принципе, мы можем даже получить этого менеджера методом getLayout() класса JPanel, но, как правило, в этом вообще нет необходимости.
Кстати, класс JPanel кроме конструктора без параметров, имеет конструктор, в котором в качестве параметра задается менеджер расположения. Поэтому вместо команд
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
можно написать:
JPanel panel = new JPanel(new FlowLayout());
Более того, по умолчанию вновь создаваемая панель имеет именно менеджер расположения FlowLayout. Поэтому в приведенном выше примере мы устанавливаем менеджера скорее для наглядности, вообще же, делать это не обязательно.
Слайд 17 Swing
Менеджер граничного размещения BorderLayout
Измененный конструктор класса
SimpleWindow :
SimpleWindow()
{ super("Пробное окно");
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().add(new JButton("Кнопка"),
BorderLayout.NORTH);
getContentPane().add(new JButton("+"), BorderLayout.EAST);
getContentPane().add(new JButton("-"), BorderLayout.WEST);
getContentPane().add(new JButton("Кнопка с длинной надписью"), BorderLayout.SOUTH);
getContentPane().add(new JButton("В ЦЕНТР!"));
setSize(250, 100);
}
Слайд 18 Swing
Менеджер размещения BorderLayout разделяет панель на пять областей: центральную, верхнюю,
нижнюю, правую и левую. В каждую из этих областей можно
добавить ровно по одному компоненту, причем компонент будет занимать всю отведенную для него область. Компоненты, добавленные в верхнюю и нижнюю области, будут растянуты по ширине, добавленные в правую и левую — по высоте, а компонент, добавленный в центр, будет растянут так, чтобы полностью заполнить оставшееся пространство панели.
При добавлении элемента на панель с менеджером размещения BorderLayout, необходимо дополнительно указывать в методе add(), какая из областей имеется в виду. Для этого служат строки с названиями сторон света: "North", "South","East", "West" и "Center". Но вместо них рекомендуется использовать константы, определенные в классе BorderLayout: NORTH, SOUTH, EAST, WEST и CENTER (поскольку в строке можно допустить ошибку и не заметить этого, а при попытке написать неправильно имя константы компилятор выдаст предупреждение). Если же использовать метод add()как обычно, с одним параметром, элемент будет добавлен в центр.
Панель содержимого имеет именно такое расположение, именно поэтому кнопка и занимала все окно целиком (она была добавлена в центральную область). Чтобы пронаблюдать эффект BorderLayout, добавим кнопки во все пять областей (пример на слайде).
Эффект будет хорошо наблюдаться, если изменять размеры окна.
Данное размещение не случайно используется в панели содержимого по умолчанию. Большинство программ пользуются областями по краям окна, чтобы расположить в них панели инструментов, строку состояния и т.п. А ограничение на один компонент в центральной области абсолютно не существенно, ведь этим компонентом может быть другая панель со множеством элементов и с любым менеджером расположения.
Слайд 19 Swing
Менеджер табличного размещения GridLayout
Измененный конструктор класса
SimpleWindow :
SimpleWindow()
{super("Пробное окно");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel =
new JPanel();
panel.setLayout(new GridLayout(2,3,5,10));
panel.add(new JButton("Кнопка"));
panel.add(new JButton("+"));
panel.add(new JButton("-"));
panel.add(new JButton("Кнопка с длинной надписью"));
panel.add(new JButton("еще кнопка"));
setContentPane(panel);
setSize(250, 100);
}
Слайд 20 Swing
GridLayout разбивает панель на ячейки одинаковой ширины и
высоты (таким образом окно становится похожим на таблицу). Каждый элемент,
добавляемый на панель с таким расположением, целиком занимает одну ячейку. Ячейки заполняются элементами по очереди, начиная с левой верхней.
Этот менеджер, в отличие от рассмотренных ранее, создается конструктором с параметрами (четыре целых числа). Необходимо указать количество столбцов, строк и расстояние между ячейками по горизонтали и по вертикали.
Слайд 21 Swing
Менеджер блочного размещения BoxLayout и класс
Box
Измененный конструктор класса SimpleWindow :
SimpleWindow()
{super("Пробное окно");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Box box = Box.createVerticalBox();
box.add(new JButton("Кнопка"));
box.add(Box.createVerticalStrut(10));
box.add(new JButton("+"));
box.add(Box.createVerticalGlue());
box.add(new JButton("-"));
box.add(Box.createVerticalStrut(10));
box.add(new JButton("Кнопка с длинной надписью"));
setContentPane(box);
setSize(250, 250);
}
Слайд 22 Swing
Менеджер BoxLayout размещает элементы на панели в строку или в
столбец.
Обычно для работы с этим менеджером используют вспомогательный класс Box, представляющий
собой панель, для которой уже настроено блочное размещение. Создается такая панель не конструктором, а одним из двух статических методов, определенных в классе Box: createHorizontalBox() и createVerticalBox().
Элементы, добавленные на панель с блочным размещением, выстраиваются один за другим. Расстояние между элементами по умолчанию нулевое. Однако вместо компонента можно добавить невидимую «распорку», единственная задача которой — раздвигать соседние элементы, обеспечивая между ними заданное расстояние. Горизонтальная распорка создается статическим методом createHorizontalStrut(int width), а вертикальная — методомcreateVerticalStrut(int height). Оба метода определены в классе Box, а целочисленный параметр в каждом из них определяет размер распорки.
Кроме того, на такую панель можно добавить еще один специальный элемент — своеобразную «пружину». Если размер панели будет больше, чем необходимо для оптимального размещения всех элементов, те из них, которые способны растягиваться, будут стараться заполнить дополнительное пространство собой. Если же разместить среди элементов одну или несколько «пружин», дополнительное свободное пространство будет распределяться и в эти промежутки между элементами. Горизонтальная и вертикальная пружины создаются соответственно методами createHorizontalGlue() иcreateVerticalGlue().
Понять особенности работы этого менеджера лучше на наглядном примере. Мы расположим четыре кнопки вертикально, поставив между двумя центральными «пружину», а между остальными — распорки в 10 пикселов.
Слайд 23 Swing
Особенности выравнивания элементов
Изменим предыдущий пример, выровняв
третью кнопку по правому краю. Заменим строку:
box.add(new JButton("-"));
На три:
JButton rightButton = new JButton("-");
rightButton.setAlignmentX(JComponent.RIGHT_ALIGNMENT);
box.add(rightButton);
Слайд 24 Swing
В примере с вертикальной панелью все кнопки оказались
выровнены по левому краю. Такое выравнивание по горизонтали принято по
умолчанию.
Однако при разработке окна программы может понадобиться, чтобы какие-то элементы были выровнены иначе, например, по правому краю или по центру. Для того, чтобы установить выравнивание любого визуального компонента (например, кнопки или панели), используются методы setAlignmentX(float alignment) — выравнивание по горизонтали и setAlignmentY(float alignment) — выравнивание по вертикали.
В качестве параметра проще всего использовать константы, определенные в классе JComponent. Для выравнивания по горизонтали служат константы LEFT_ALIGNMENT (по левому краю), RIGHT_ALIGNMENT (по правому краю) и CENTER_ALIGNMENT (по центру). Для выравнивания по вертикали —BOTTOM_ALIGNMENT (по нижнему краю), TOP_ALIGNMENT (по верхнему краю) и CENTER_ALIGNMENT (по центру).
Однако выравнивание работает несколько иначе, чем ожидается. Чтобы это обнаружить, изменим предыдущий пример, выровняв третью кнопку по правому краю (см. слайд).
Нам пришлось ввести переменную для обращения к этой кнопке, поскольку теперь нам нужно выполнить с ней не одно, а два действия: установка выравнивания по правому краю и добавление в панель. Прежний прием — одновременное создание кнопки и передача ее в качестве параметра в метод — здесь не сработает.
После запуска программы мы увидим окно, в котором кнопки расположены не так, как, наверное, ожидалось. Мы привыкли, что выравнивание по правому краю прижимает объект к правому краю контейнера, но в данном случае перестроились все элементы, причем кнопка с выравниванием по правому краю оказалась самой левой.
Объяснение просто. При выравнивании по правому краю объект не прижимается к правому краю компонента. Вместо этого он прижимается правым краем к невидимой линии выравнивания. Все остальные компоненты прижимаются к этой линии своим левым краем, поэтому и получается наблюдаемый эффект.
Слайд 25 Swing
Единственная трудность для начинающего разработчика может оказаться в
том, что не всегда легко понять, где именно пройдет эта
линия. Ее положение зависит от размеров и выравнивания всех элементов контейнера. Однако легко запомнить простое правило: если все элементы в контейнере выровнены одинаково, мы получим привычное поведение (как это и было в предыдущем примере, когда все компоненты были выровнены влево и линия в результате прижалась к левому краю панели.
Замечание. Параметр выравнивания на самом деле представляет собой вещественное число в диапазоне от 0 до 1. Он показывает, какая часть компонента окажется слева от линии выравнивания, т.е. в каких пропорциях компонент будет «разрезан». Константы LEFT_ALIGNMENT и TOP_ALIGNMENT на самом деле равны 0, RIGHT_ALIGNMENT и BOTTOM_ALIGNMENT равны 1, а CENTER_ALIGHNMENT — 0.5. Можно подставлять эти числа напрямую (хотя использование констант значительно повышает наглядность!), а можно выбрать любое другое число от 0 до 1 и настроить совершенно произвольное выравнивание.
Слайд 26 Swing
Ручное размещение элементов
Методы для задания координат
элемента:
setLocation(int x, int y),
setLocation(Point point)
Размещение элемента b в точности в
то место, которое занимает элемент a:
b.setLocation(a.getLocation());
Методы для задания размера элемента:
setSize(int width, int height),
setSize(Dimension size)
b.setSize(a.getSize());
Слайд 27 Swing
Если в качестве менеджера размещения панели установить null, элементы
не будут расставляться автоматически. Координаты каждого элемента необходимо в этом
случае указать явно, при этом они никак не зависят от размеров панели и от координат других элементов. По умолчанию координаты равны нулю (т.е. элемент расположен в левом верхнем углу панели). Размер элемента также необходимо задавать явно (в противном случае его ширина и высота будут равны нулю и элемент отображаться не будет). Координаты элемента можно задать одним из следующих методов: setLocation(int x, int y) или setLocation(Point point).
Эти методы работают аналогично, устанавливая левый верхний угол элемента в точку с заданными координатами. Разница в способе задания точки. Можно представить точку двумя целыми числами, а можно объектом класса Point. Класс Pointп о сути представляет собой ту же пару чисел, его конструктор имеет вид Point(int x, int y). Получить доступ к отдельной координате можно методами getX() и getY().
Можно задаться вопросом: зачем использовать класс Point, если можно просто передать пару чисел? Но дело в том, что многие полезные методы возвращают результат — координаты некоторой точки — в виде объекта этого класса. Например, метод getLocation(), возвращающий координаты элемента. Предположим, нам нужно поместить элемент b в точности в то место, которое занимает элемент a. Этого легко добиться одной строкой: b.setLocation(a.getLocation());
Размер элемента задается одним из двух методов: setSize(int width, int height) или setSize(Dimension size). Эти методы работают одинаково — разница, как и в прошлый раз, в способе передачи параметра. Класс Dimension, аналогично классу Point, просто хранит два числа, имеет конструктор с двумя параметрами: Dimension(int width, int height) и позволяет получить доступ к своим составляющим — ширине и высоте — с помощью простых методов getWidth() и getHeigth(). Для того, чтобы получить текущий размер элемента, можно воспользоваться методом getSize(), возвращающего объект класса Dimension. Элемент b можно сделать точно такого же размера, как элемент a, выполнив команду: b.setSize(a.getSize());
Слайд 28 Swing
Ручное размещение элементов
Измененный конструктор класса SimpleWindow :
SimpleWindow()
{super("Пробное окно");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel = new
JPanel();
panel.setLayout(null);
JButton button = new JButton("Кнопка");
button.setSize(80, 30);
button.setLocation(20,20);
panel.add(button);
button = new JButton("Кнопка с длинной надписью");
button.setSize(120, 40);
button.setLocation(70,50);
panel.add(button);
setContentPane(panel);
setSize(250, 150);
}
Слайд 29 Swing
Создадим панель, с которой не будет связано никакого
менеджера размещения и вручную разместим на ней две кнопки.
Мы используем
одну и ту же переменную button для обращения к обеим кнопкам (причем, второй раз ее описывать не нужно). В самом деле, осуществив все необходимые операции с первой кнопкой и зная, что обращаться к ней нам больше не понадобится, мы используем «освободившуюся» переменную для манипуляций со второй.
Слайд 30 Swing
Автоматическое определение размеров компонентов
Методы возвращают минимально
допустимый, максимально допустимый и предпочтительный размеры визуального компонента:
getMinimumSize(),
getPreferredSize(),
getMaximumSize().
Всеми тремя размерами
можно управлять с помощью соответствующим методов set:
setMinimumSize(Dimension size),
setPreferredSize(Dimension size),
setMaximumSize(Dimension size).
Чаще всего используется простой прием, когда элементу «не рекомендуется» увеличиваться или уменьшаться относительно своих предпочтительных размеров. Это легко сделать командой:
element.setMinimumSize(element.getPreferredSize());
Слайд 31 Swing
Если у панели есть любой менеджер размещения, она
игнорирует явно заданные размеры и координаты всех своих элементов. В
этом легко убедиться, заменив в предыдущем примере команду panel.setLayout(null) на panel.setLayout(new FlowLayout()). Менеджер размещения сам определяет координаты и размеры всех элементов.
Способ определения координат элементов очевидным образом вытекает из алгоритмов работы каждого менеджера и, таким образом, детально рассмотрен нами выше.
Мы также отмечали, что в некоторых случаях компоненты стараются заполнить все доступное им пространство. Например, всю центральную область в случае менеджера BorderLayout или всю ячейку в менеджере GridLayout. А в панели с менеджером FlowLayout, напротив, элементы никогда не пытаются выйти за определенные границы. Рассмотрим, что это за границы.
Каждый визуальный компонент имеет три типа размеров: минимально допустимый, максимально допустимый и предпочтительный. Узнать, чему равны эти размеры для данного компонента можно с помощью соответствующих методов: getMinimumSize(), getPreferredSize(), getMaximumSize().
Методы возвращают результат типа Dimension. Они запрограммированы в соответствующем классе. Например, у кнопки минимальный размер — нулевой, максимальный размер не ограничен, а предпочтительный зависит от надписи на кнопке (вычисляется как размер текста надписи плюс размеры полей).
Менеджер FlowLayout всегда устанавливает предпочтительные размеры элементов. Менеджер BorderLayout устанавливает предпочтительную ширину правого и левого, а также предпочтительную высоту верхнего и нижнего. Остальные размеры подгоняются под доступное пространство панели. Менеджер GridLayout пытается подогнать размеры всех элементов под размер ячеек. Менеджер BoxLayout ориентируется на предпочтительные размеры.
Когда элемент старается занять все доступное ему пространство, он «учитывает» пожелания не делаться меньше своих минимальных или больше максимальных.
Всеми тремя размерами можно управлять с помощью соответствующим методов set (см. слайд).
Слайд 32 Swing
«Упаковка» окна
setSize(250, 100); -> pack()
Слайд 33 Swing
В рассмотренных выше примерах мы явно задавали размер
окна методом setSize(). Но когда используется какой-либо менеджер расположения, расставляющий элементы
и изменяющий их размеры по собственным правилам, трудно сказать заранее, какие размеры окна будут самыми подходящими.
Безусловно, наиболее подходящим будет вариант, при котором все элементы окна имеют предпочтительные размеры или близкие к ним.
Если вместо явного указания размеров окна, вызвать метод pack(), они будут подобраны оптимальным образом с учетом предпочтений всех элементов, размещенных в этом окне.
Оцените работу этого метода, заменив в каждом из вышеприведенных примеров команду setSize(250, 100) на команду pack(). Заметьте, что когда панель не имеет метода размещения, эта команда не работает (поскольку панель не имеет алгоритма для вычисления своего предпочтительного размера).
Слайд 34 Swing
Пример. Создание шести панелей с различными
рамками и размещение их в виде таблицы :
Добавить в файл
SimpleWindow.java: import javax.swing.border.*; и в класс SimpleWindow метод createPanel
// метод создания новой панели
private JPanel createPanel(Border border, String text)
{ JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JButton(text));
panel.setBorder(new CompoundBorder(new EmptyBorder(12,12,12,12), border));
return panel;
}
Слайд 35 Swing
Измененный конструктор класса SimpleWindow :
SimpleWindow()
{super("Пробное окно");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2,3,5,10));
panel.add(createPanel(new TitledBorder("Рамка с заголовком"), "TitledBorder"));
panel.add(createPanel(new EtchedBorder(), "EtchedBorder"));
panel.add(createPanel(new BevelBorder(BevelBorder.LOWERED), "BevelBorder"));
panel.add(createPanel(new SoftBevelBorder(BevelBorder.RAISED), "SoftBevelBorder"));
panel.add(createPanel(new LineBorder(Color.ORANGE, 4), "LineBorder"));
panel.add(createPanel(new MatteBorder(new ImageIcon("1.gif")), "MatteBorder"));
setContentPane(panel);
pack();
}
Слайд 36 Swing
Рассмотрим пример. В этом примере мы создадим шесть
панелей с различными рамками и разместим их в виде таблицы.
Чтобы не описывать шесть раз процедуру создания новой панели, вынесем ее в отдельный метод (см. слайд).
Метод createPanel() создает панель с кнопкой во весь свой размер. В качестве параметра передается надпись на кнопке и рамка, которую необходимо добавить к панели. Рамка добавляется не напрямую, а путем композиции с пустой рамкой. Этот прием часто используется, чтобы рамка не прилипала к краю панели.
Теперь шесть раз воспользуемся этим методом в конструкторе окна программы.
Этот пример показывает, с помощью каких конструкторов создаются различные рамки и как они выглядят. В нем использованы два новых класса: Color и ImageIcon.
Класс Color предназначен для работы с цветом. В нем есть несколько констант, описывающих наиболее распространенные цвета. В частности, к таковым относится Color.ORANGE.
Класс ImageIcon описывает графическое изображение. Параметр его конструктора — это путь к файлу, из которого изображение может быть загружено. В примере используется относительное имя файла «1.gif». Чтобы объект ImageIcon был успешно создан, файл с таким именем должен быть помещен в папку проекта.