Менеджеры размещения в Java
Перед использованием управляющих компонентов (например, кнопок) их надо расположить на форме в нужном порядке. Вместо ручного расположения применяются менеджеры размещения, определяющие способ, который панель использует для задания порядка размещения управляющего элемента на форме. Менеджеры размещения контролируют, как выполняется позиционирование компонентов, добавляемых в окна, а также их упорядочение. Если пользователь изменяет размер окна, менеджер размещения переупорядочивает компоненты в новой области так, чтобы они оставались видимыми и в то же время сохранили свои позиции относительно друг друга.
Менеджер размещения представляет собой один из классов FlowLayout, BorderLayout, GridLayout, CardLayout, BoxLayout, реализующих интерфейс LayoutManager, устанавливающий размещение.
Класс FlowLayout – менеджер поточной компоновки. При этом компоненты размещаются от левого верхнего угла окна, слева направо и сверху вниз, как и обычный текст. Этот менеджер используется по умолчанию при добавлении компонентов в апплеты. При использовании библиотеки AWT менеджер FlowLayout представляет собой класс, объявленный следующим образом:
public class FlowLayout extends Object
implements LayoutManager, Serializable
В следующем примере демонстрируются возможности поточной компоновки различных элементов управления.
/* пример # 1 : поточная компоновка по центру: FlowLayoutEx.java */
public class FlowLayoutEx extends JApplet <
private Component c[] = new Component[9];
//установка менеджера размещений
setForeground(Color.getHSBColor(1f, 1f, 1f));
Похожие посты:
Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.
Введение в JavaFx и работа с layout в примерах
Доброго времени суток. В этой статье я расскажу основы работы с классами пакета javafx.scene.layout.* (BorderPane, AnchorPane, StackPane, GridPane, FlowPane, TilePane, HBox, VBox) и их особенностями в пошаговых примера и иллюстрациях. Также в кратце пробежимся по иерархии классов JavaFx.
После установки Eclipse и плагина e(fx)lipse создадим новый проект:
Выбираем JavaFx проект:
По дефолту Eclipse создаст такую заготовку:
На сцену добавляется корневой узел, им должен быть класс унаследованный от Parent (узел, который может иметь детей) корневой узел добавляется на сцену (специальный контейнер для всего контента графа узлов), а она в свою очередь на стейжд, который и показывается.
Давайте разберемся с иерархией классов JavaFx:
Самым базовым абстрактным классом является Node — узел в графе сцены, наследникам предоставляются поля для настройки размеров: (minWidth — минимальная ширина, minHeight — минимальная высота, prefWidth — предпочтительная ширина, prefHeight — предпочтительная высота, maxWidth — максимальная ширина, maxHeight — максимальная высота).
Координаты узла: getLayoutX() и getLayoutY()
relocate(double x, double y) — изменяет координаты узла, если необходимо настроить положение каждой координаты по отдельности, используйте setLayoutX(double value) и setLayoutY(double value)
Важно понимать, что выставленные координаты и размеры (pref то есть prefer — предпочтительно) при компоновке, в зависимости от иерархии графа узлов и их настроек могу отличаться от ожидаемых. Примеры приведу чуть позже.
Node не может содержать дочерних элементов это и логично, для этого существует Parent прямой наследник Node, в который можно добавлять и удалять дочерние узлы. Кстати, говоря, есть классы которые представляю узлы, но не содержат дочерние узлы: Camera, Canvas, ImageView, LightBase, MediaView, Parent, Shape, Shape3D, SubScene, SwingNode.
Нас сегодня интересует подгруппа наследников класса Region (базовый класс всех лайуат контейнеров) в частности поговорим о основных потомках класса Pane о панелях, которые чаще всего требуются в повседневной разработке.
BorderPane
Это специальная панель которая располагает свою дочерние узлы верхней(setTop(Node)), нижней(setBottom(Note)), левой(setLeft(Node)), правой(setRight(Node)) и центральной(setCenter(Node)) позициях, добавим несколько кнопок во все эти позиции на BotderPane:
У секции top и bottom приоритет, поэтому они сужаю по высоте все остальные:
При попытке задать координаты к примеру у верхней кнопки:
Кнопка не изменит своего положения, почему так происходит? При компоновке детей в методе layoutChildren класса BorderPane переопределяется позиция каждого узла с учетом всех настроек. Решений исправить есть несколько, например поместить (обернуть) кнопку в дополнительный подходящий контейнер, например в базовую для всех панелей
Потому как Pane никак не переопределяет положение своих детей, мы получаем нужное смещение:
Можно не оборачивать кнопку, а просто выставить у нее внешний отступ c помощью статического метода setMargin(Node child, Insets value):
Insets — вспомогательный класс для настройки отступов, конструктор у него перегружен, может принимать один аргумент для все сторон, так и для каждой стороны в отдельности, пока мы настроили для все сторон один отступ, вот что мы получили:
Уберем отступы снизу и справа и получим желаемое смещение кнопки:
StackPane
Теперь давайте рассмотрим ситуацию в которой панель навязывает детям не только позицию, но и пытается их растянуть по всей ширине и высоте, заполнив всю область контента, заменим BorderPane и добавим туда сначала TextArea и Button.
Кстати, для добавления нескольких узлов в нужном порядке можно использовать метод:
Что мы видим, текстовое поле растянулись по нашей панели, а кнопка центрировалась:
Центрирование можно корректироваться с помощью setAlignment(Pos)
Сделать внутренний отступ с помощью setPadding(Insets)
Можно сделать индивидуальную настройку центрирования и отступов каждого узла с помощью статических методов:
AnchorPane
Якорная панель позволяет края дочерних узлов привязывать смещениями к краям панели, рассмотрим пример:
Добавим кнопку и привяжем ее к правому краю:
AnchorPane root = new AnchorPane();
Button button = new Button(«Button in AnchorPane»);
root.getChildren().add(button);
AnchorPane.setRightAnchor(button, 10.0);
Добавим привязку к нижнему краю:
Теперь в левому краю и верхнему:
Получаем что края кнопки теперь жестко привязаны к краям панели, если начать тянуть окно, кнопка будет также тянуться.
GridPane
Рассмотрим очень полезную сеточную панель, добавление детей в эту панель необходимо делать через метод add(Node child, int columnIndex, int rowIndex) в котором первый параметр добавляемый узле, второй номер колонки, третий номер строки, вот простой пример:
Мы видим, что узлы можно добавлять в любую ячейку, пустые столбцы и строки создаются автоматически:
Для работы с колонками, есть специальный класс ColumnConstraints, для этого надо создать колонки, настроить их и добавить их в GridPane, в примеру если мы хотим выставить ширины первой колонки 130, а второй 20%:
Это самые базовые возможности, потребуется написать отдельную статья, для охвата всех тонкостей настройки GridPane.
FlowPane
Давайте сразу к примеру из него сразу станет все понятно, добавим шесть кнопок в FlowPane:
Посмотрим результат, кнопка выводятся одна за другой (по дефолту у FlowPane горизонтальный вывод Orientation.HORIZONTAL)
Теперь при уменьшении окна по ширине, мы видим что дочерние узлы начинают переносится:
И соответственно если выставить вертикальную ориентацию
При при уменьшении высоты окна получаем перенос:
Вертикальные и горизонтальные отступы между элементами можно настроиться с помощью:
TilePane
Работа этой панели схожа с работой FlowPane, отличие в том что дочерние узлы помещаются в сетку ячейки которой одинакового размера, приведем предыдущий пример, но в этот раз пусть одна кнопка будет больших размеров, чем остальные:
Как мы видим все узлы теперь находятся в «тайла» одинаковых размеров, растянутых по наибольшему узлу.
HBox и VBox
Это обычные горизонтальный и вертикальный списки, комбинируйте их, чтобы добиться нужного результата:
Это все наследники класса Pane, спасибо за внимание.
Менеджеры расположения Layout
Менеджер расположения (layout manager) определяет, каким образом на форме будут располагаться компоненты. Независимо от платформы, виртуальной машины, разрешения и размеров экрана менеджер расположения гарантирует, что компоненты будут иметь предпочтительный или близкий к нему размер и располагаться в том порядке, который был указан программистом при создании программы.
На странице представлено описание следующих менеджеров расположения и примеров :
Исходные коды примеров различных менеджеров расположения, рассмотренных на странице можно скачать здесь (13.4 Кб).
В Swing менеджер расположения играет еще большую роль, чем обычно. Он позволяет не только сгладить различия между операционными системами, но к тому же дает возможность с легкостью менять внешний вид приложения, не заботясь о том, как при этом изменяются размеры и расположение компонентов.
Поддержка менеджеров расположения встроена в базовый класс контейнеров java.awt.Container. Все компоненты библиотеки Swing унаследованы от базового класса JComponent, который, в свою очередь, унаследован от класса Container. Таким образом, для любого компонента Swing можно установить менеджер расположения или узнать, какой менеджер им используется в данный момент. Для этого предназначены методы setLayout() и getLayout().
Конечно, изменять расположение желательно только в контейнерах, которые предназначены для размещения в них компонентов пользовательского интерфейса, то есть в панелях (JPanel) и окнах (унаследованных от класса Window). Не стоит менять расположение в кнопках или флажках, хотя такая возможность имеется. В стандартной библиотеке Java существует несколько готовых менеджеров расположения, и с их помощью можно реализовать абсолютно любое расположение.
Вызов менджера расположения, revalidate
Контейнер окна вызывает методы менеджера расположения каждый раз при изменении своих размеров или при первом появлении на экране. Кроме этого, можно программно запросить менеджер расположения заново расположить компоненты в контейнере: для этого служит так называемая проверка корректности (валидация) контейнера и содержащихся в нем компонентов. Проверка корректности очень полезна, если интерфейс приложения меняется динамически. Например, если динамически меняются размеры компонентов (во время выполнения программы изменяется текст надписи или количество столбцов таблицы — все это приведет к изменению размеров компонентов). После изменений компонентам может не хватать прежних размеров или наоборот, прежний размер будет для них слишком велик. Для этого и предназначена проверка корректности. Выполнить проверку корректности для любого компонента Swing, будь это контейнер или отдельный компонент, позволяет метод revalidate(), определенный в базовом классе библиотеки JComponent.
Менеджер расположения размещает добавляемые в контейнер компоненты в некотором порядке согласно реализованного в нем алгоритма, и определяет их некоторый размер. При этом он обычно учитывает определенные свойства компонентов :
Описание бизнес-логики работы менеджера расположения
Логика работы менеджера расположения происходит следующим образом : он ждет прихода сигнала от контейнера окна, требующего расположить в нем компоненты. Этому соответствует вызов метода layoutContainer() интерфейса LayoutManager. В методе layoutContainer() и происходит основная работа по расположению компонентов в контейнере.
Менеджер расположения учитывает различные размеры и свойства компонентов и контейнера, и должен расположить компоненты на определенных позициях в контейнере, вызывая для каждого из них метод setBounds(), позволяющий указать в пикселах в системе координат контейнера прямоугольник, который будет занимать компонент. Для сложных менеджеров расположения с гибким поведением это означает массу работы и сложные вычисления, однако простые алгоритмы расположения компонентов реализовать совсем несложно.
Ниже представлен пример разработки менеджера вертикального расположения компонентов VerticalLayout. Он располагает компоненты вертикально с расстоянием между ними в 5 пикселов и использует для всех компонентов предпочтительный размер.
Менеджер расположения VerticalLayout реализует интерфейс LayoutManager. Самым важным методом является layoutContainer(), который определяет расположения всех компонентов, содержащиеся в контейнере. Алгоритм функционирования менеджера расположения не сложный : размещение компонентов по вертикали, отделяя их друг от друга расстоянием в 5 пикселов; все компоненты имеют предпочтительный размер. Чтобы реализовать алгоритм выполняются следующие шаги :
Таким образом, менеджер VerticalLayout разместит все компоненты контейнера друг над другом на расстоянии в 5 пикселов. Следует обратить внимание, что компоненты отделены и от левой границы контейнера.
Метод addLayoutComponent() предназначен для добавления компонентов в список менеджера расположения, а метод removeLayoutComponent() для удаления компонентов из списка. addLayoutComponent() позволяет ассоциировать с компонентом строку, которая может быть использована менеджером расположения как рекомендация относительно того, где именно необходимо разместить данный компонент. Наш пример менеджера расположения в отличие от BorderLayout не поддерживает подобных рекомендаций.
Две функции менеджера (предпочтительный preferredLayoutSize() и минимальный minimumLayoutSize()) сообщают размеры контейнера. Для нашего простого менеджера расположения минимальный и предпочтительный размеры контейнера совпадают, их вычисляет метод calculateBestSize(). Для вычисления оптимального размера контейнера в цикле выполняется поиск компонента с самой большой длиной. К найденной длине добавляется 5 пикселов в качестве отступа от левой границы контейнера и получаем оптимальную длину контейнера. Для высоты вычисления чуть сложнее : необходимо сложить высоты всех находящихся в контейнере компонентов, а также прибавлять к ним расстояние в 5 пикселов между всеми компонентами. Полученная сумма и является оптимальной высотой контейнера.
Для тестирования менеджера вертикального расположения в методе main() создаем небольшое окно с рамкой JFrame. Создаем панель с устанавленным менеджером расположения VerticalLayout. В панель добавляется пара кнопок и текстовое поле. Созданную панель размещаем в панели содержимого, после чего окно выводится на экран. На следующем скриншоте представлен интерфейс окна примера использования вертикального менеджера расположения компонентов.
Знание основных принципов работы менеджера расположения позволяет глубже понять технологию размещения компонентов в контейнере при использовании библиотеки Swing.
Полярное расположение BorderLayout
Менеджер расположения BorderLayout иммет отличия от остальных. Чтобы добавить с его помощью компонент в методе add() необходимо использовать дополнительный параметр, который определяет область контейнера для размещения компонента. В таблице перечислены допустимые значения этого параметра.
Значение | Строка | Описание |
---|---|---|
BorderLayout.NORTH | North | Компонент располагается вдоль верхней границы окна и растягивается на всю его ширину. Обычно в этом месте размещается панель инструментов. |
BorderLayout.SOUTH | South | Компонент располагается вдоль нижней границы и растягивается на всю ширину окна. Такое положение характерно для строки состояния. |
BorderLayout.WEST | West | Компонент располагается вдоль левой границы окна и растягивается на всю его высоту; при этом учитываются размеры северных и южных компонентов, имеющих приоритет. |
BorderLayout.EAST | East | Компонент располагается вдоль правой границы окна. В остальном его расположение аналогично западному компоненту. |
BorderLayout.CENTER | Center | Компонент помещается в центр окна, занимая максимально возможное пространство. |
Рекомендации : на север помещайте панель инструментов вашего приложения. На юг помещайте строку состояния. Оставляйте западные и восточные зоны окна свободными — только в этом случае панель инструментов можно будет перетаскивать. Для главного окна вашего приложения всегда используйте расположение BorderLayout.
Рассмотрим простой BorderLayout пример. В примере создается окно JFrame, в котором менеджер BorderLayout используется по умолчанию. Во все доступные зоны добавляются компоненты :
В примере метод установки менеджера расположения setLayout() не вызывался. В окнах JFrame (также в окнах JWindow и JDialog) расположение BorderLayout применяется автоматически c принимаемой по умолчанию константой Center. При использовании строк в качестве параметров метода add() надо быть внимательным. Со строкой легко сделать трудно обнаруживаемую ошибку, в то время как ошибку при использовании констант сразу же обнаружит компилятор.
Интерфейс примера BorderLayout представлен на следующем скриншоте.
Возможности полярного расположения довольно ограничены. Оно создано специально для окон, но иногда может помочь и в более сложных случаях.
Последовательное расположение FlowLayout
Менеджер последовательного расположение FlowLayout размещает компоненты в контейнере слева направо, сверху вниз. При полном заполнении компонентами строки контейнера FlowLayout переходит на следующую строку вниз. Данное расположение устанавливается по умолчанию в панелях JPanel. Основным свойством FlowLayout является определение предпочтительного размера компонентов. Например, размер метки с текстом JLabel соответствует размеру текста. Рассмотрим простой пример FlowLayout :
Конструктор класса FlowLayout имеет три перегруженные версии: без параметров, с параметрами выравнивания компонентов, с параметрами выравнивания компонентов и расстояний между ними. В примере использована вторая версия, устанавливающая последовательное расположение по центру.
На следующем скриншоте показан интерфейс программы для двух разных размеров окна по горизонтали.
На правом скриншоте размер окна не позволил менеджеру FlowLayout разместить компоненты в одной строке, и один компонент сместился в следующую строку.
При последовательном расположении менеджер FlowLayout всегда сохраняет предпочтительный размер компонентов. Если места в контейнере становится мало, то FlowLayout просто прячет «лишние» компоненты, а не уменьшает их размеры.
Также к важным свойствам менеджера расположения FlowLayout следует отнести то, что при вызове метода preferredLayoutSize() или minimumLayoutSize(), позволяющего узнать предпочтительный и минимальный размеры контейнера, в котором этот менеджер действует, метод возвращает размер, соответствующий ситуации расположения всех компонентов в одну строку. Это особенно важно при совмещении последовательного расположения с другими вариантами расположения. Вследствие этого свойства менеджеры других вариантов расположения будут стараться найти достаточно места для размещения компонентов в одну строку.
Поэтому использовать последовательное расположение следует только в контейнере, где достаточно места, или там, где контейнеру некуда будет «прятать» свои компоненты. Пример совмещении последовательного расположения с табличным представлен на этой странице здесь. Тем не менее, этот простотой менеджер расположения FlowLayout очень хорош при организации несложных вариантов расположения.
Табличное расположение GridLayout
Менеджер расположения GridLayout представляет контейнер в виде таблицы с ячейками одинакового размера. Количество строк и столбцов можно указать в конструкторе. Имеется возможность задать произвольное количество либо строк, либо столбцов, но не одновременно. Все ячейки таблицы имеют одинаковый размер, равный размеру самого большого компонента, находящегося в таблице.
В примере задается произвольное количество столбцов. Для этого в конструкторе вместо конкретного числа столбцов указывается ноль. Аналогично можно задать и произвольное количество строк в таблице.
Интерфейс работы программы представлен на следующем скриншоте.
Если произвольно увеличить размер окна, то менеджер расположения GridLayout также занимает все место, доступное в данный момент в окне, и пропорционально увеличивает размеры компонентов. Если уменьшить окно, то GridLayout также пропорционально уменьшит размеры компонентов. Основные свойства менеджера табличного расположения :
Чаще всего совмещают панели с различными менеджерами расположения для получения необходимого интерфейса окна. В следующем примере совмещаем менеджер табличного расположения компонентов GridLayout с менеджером последовательного расположения FlowLayout, которое никогда не делает содержащиеся в нем компоненты больше их предпочтительного размера. Для этого создадим элемент пользовательского интерфейса, встречающийся практически в любом диалоговом окне, а именно строку кнопок (кнопки ОК и Отмена). Табличное расположение придаст кнопкам одинаковый размер, а последовательное расположение не даст им «расплыться» и заодно выровняет их по правому краю.
Пример совмещения табличного GridLayout и последовательного FlowLayout расположения компонентов
В данном примере как бы не изменять размер окна полярное расположение заставит панель с кнопками разместиться вдоль нижней границы окна, а последовательное расположение заставит их прижаться к правому краю. Интерфейс работы программы представлен на следующем скриншоте.
Менеджер расположения GridBagLayout
Менеджер расположения GridBagLayout подобно табличному менеджеру устанавливает компоненты в таблицу. Но он дает возможность определять для компонентов разную ширину и высоту колонок и строк таблицы. Фактически GridBagLayout позволяет получить абсолютно любое расположение компонентов.
Пример менеджера расположения GridBagLayout
При использовании менеджера расположения GridBagLayout необходимо настраивать класс GridBagConstraints для каждого добавляемого компонента. Это существенно усложняет процесс разработки. Поэтому GridBagLayout используется большей частью при автоматизированной разработке интерфейса, при которой мышью указывается расположение компонентов, а система требуемым образом настраивает менеджер GridBagLayout.
Пользовательский интерфейс примера GridBagLayout представлен на следующих скриншотах. На нижнем скриншоте представлен интерфейс для уменьшенного размера окна.
Менеджер расположения CardLayout
Менеджер CardLayout можно использовать для создания так называемых вкладок (tabs), выбирая которые будут избранно открываться разные панели, занимающие одно и то же место в интерфейсе окна. В библиотеке Swing данную задачу можно решить с использованием класса JTabbedPane, организовывающего управление панелями с вкладками.
Пример менеджера расположения CardLayout
Пользовательский интерфейс примера менеджера расположения CardLayout представлен на следующих скриншотах. На верхних скриншотах представлен интерфейс окна для разных размеров. На нижнем скриншоте представлен интерфейс окна для вкладки с тестовым полем.
Менеджер расположения BoxLayout
Пример менеджера расположения BoxLayout
Пользовательский интерфейс примера менеджера расположения BoxLayout представлен на следующих скриншотах. На верхнем скриншоте представлен интерфейс окна с вертикальным расположением компонентов. На нижнем скриншоте компоненты размещены в горизонтальной плоскости.
Менеджер расположения GroupLayout
Менеджер расположения компонентов GroupLayout появился только в Java 6. Он раскладывает компоненты по группам. Группы имеют горизонтальное и вертикальное направление и могут быть параллельными и последовательными. В последовательной группе у каждого следующего компонента координата вдоль оси на единицу больше (имеется в виду координата в сетке), в параллельной – компоненты имеют одну и ту же координату.
Пример менеджера расположения GroupLayout
Интерфейс окна примера менеджера расположения GroupLayout представлен на следующем скриншоте.
Менеджер расположения SpringLayout
Несмотря на универсальность менеджера расположения SpringLayout, действие его весьма специфично и не похоже на действие ни одного из уже рассмотренных выше менеджеров расположения.
С каждым компонентом ассоциируется особый информационный объект SpringLayout, который позволяет задать расстояние (в пикселах) между парой границ различных компонентов. Границ у компонента четыре — это его северная, восточная, западная и южная стороны. Можно задавать расстояние и между границами одного и того же компонента: к примеру, задав расстояние между северной и южной сторонами одного компонента, вы укажете его высоту. По умолчанию все компоненты имеют предпочтительный размер, однако SpringLayout учитывает и два остальных размера, не делая компоненты меньше минимального и больше максимального размеров.
На первом этапе работы менеджера SpringLayout все компоненты находятся в начале координат контейнера и имеют предпочтительный размер. Чтобы разместить их по нужным позициям, обычно проводят следующие действия: первый компонент отделяют некоторым расстоянием от границы контейнера, второй отделяют от первого расстоянием между нужными границами, далее размещают третий компонент и т.д.
Пример менеджера расположения SpringLayout
Интерфейс окна примера менеджера расположения SpringLayout представлен на следующем скриншоте.
Интерфейс диалогового окна авторизации
Интерфейс примера диалогового окна авторизации LoginDialog представлен на следующем скриншоте.
Исходный код примера LoginDialog в виду его большого размера не приводится. Но его можно скачать вместе с остальными примерами.