Данная статья задумана для того, чтобы объяснить на начальном уровне идею менеджеров разметки (layout manager), дать примеры использования основных менеджеров и показать вариант, как можно написать свой собственный менеджер разметки. Все замечания автор с удовольствием принимает.

Итак – зачем нужен Layout Manager?
Если мы вспомним, что язык JAVA изначально создавался как язык, предназначенный для разработки приложений, которые способны работать на различных платформах и, что в данном случае более важно, устройствах, то необходимость такого рода интерфейса становится очевидна. Необходим механизм, который позволит одному и тому же приложению работать при различных разрешениях и при различных формах экрана.
Кто уже создавал различные приложения GUI, тот наверняка сталкивался с проблемами типа: как сделать так, чтобы при изменении размера формы расположенные на ней компоненты каким-либо образом вели себя. Либо пропорционально уменьшались (увеличивались) в размерах, либо оставались такого же размера, проявлялись полосы скроллинга, компоненты как-нибудь перемещались по экрану и так далее. И каждый раз приходилось придумывать некие программные механизмы, которые, по сути, занимались тем, что обрабатывали событие типа «окно изменило свои размеры». А дальше происходило следующее: на основе некого алгоритма программист вынужден менять размеры кнопок, панелей, списков и прочая. Автор сам это делал не один раз и особого восторга от этого не испытывал. Само собой у каждого со временем накапливались некоторые уже стандартные наработки.
Так вот основная идея LayoutManager состоит в том, что программисту предоставляется уже готовые варианты размещения компонентов на экране (это и есть стандартные Layout managers, о которых мы поговорим немного позже), а также дается возможность самому описать механизм (алгоритм) который будет корректно обрабатывать такую ситуацию. Любой контейнер (Container и его подклассы) имеет метод setLayout(LayoutManager mgr). Задавая новый layout manager Вы говорите контейнеру, какой алгоритм он должен использовать при размещении компонентов.

Какие бывают layout manager’ы?
Всего в Java SE (Standart Ediotion) API описано порядка 20 различных layout manager’ов. Мы рассмотрим на взгляд автора наиболее распространенные – задавая различные комбинации менеджеров для контейнеров на Вашей форме, Вы можете добиться практически любого нужного Вам результата. Если Вы считаете, что какой-то неупомянутый менеджер должен быть упомянут – пишите. Этот layout manager будет добавлен.

Прежде чем рассматривать конкретные менеджеры необходимо остановится на следующем моменте – все контейнеры для размещения своих компонент используют характеристики этих компонентов. А фактически — размеры. На основании этих данных и вычисляется расположение компонентов. К методам, которые отвечают за это, относятся:
getMaximumSize() – возвращает максимально допустимый размер компонента.
getMinimumSize() – возвращает минимально допустимый размер компонента.
getPrefferedSize() – возвращает наиболее предпочтительный размер компонента. Для понимания – кнопка вряд ли требует размера гораздо большего, чем надпись.
Если, например, Вам необходимо, чтобы Ваша панель слева имела постоянную ширину – просто переопределите нужные методы у панели, создав свой производный класс, и возвращайте нужную Вам величину. Установленный LayoutManager будет учитывать Ваши пожелания. В примере, где мы создадим свой собственный layout Вы сможете поэкспериментировать с этими методами, удалив и добавив комментарии в указанных местах.

Итак, мы рассмотрим такие менеджеры: FlowLayout, BoxLayout, BorderLayout, GridLayout, CardLayout, GridBagLayout.

FlowLayout – самый простой layout manager. Работает крайне примитивно – просто рисует в строку все компоненты в том порядке, в котором они были помещены в контейнер. Если места в строке уже не хватает, то переносит оставшиеся компоненты на другую строку. Чем-то это напоминает написание текста в текстовом редакторе. Посмотрите пример, в котором на форму кладется просто много кнопок. Если Вы попробуйте поменять размер формы (особенно хорошо видно если менять только ширину) ширину, то увидите, что расположение кнопок будет меняться. Данный layout вряд ли может быть использован при составлении сложных графических интерфейсов. Но он может быть использован для несложных задач выравнивания – данный layout позволяет задать вариант выравнивания (слева, по центру, справа) а также расстояние между компонентами.

BoxLayout – тоже достаточно простой layout. Позволяет располагать компоненты вдоль одной из осей – вертикально или горизонтально. В конструкторе указывается, какой вариант предпочитает использовать программист. Сам по себе данный layout используется крайне редко, но использовать его в комплексе бывает достаточно удобно. Например, на какой-нибудь панели со скроллингом удобно расположить компоненты вертикально.

BorderLayout – данный layout уже более сложен. Компоненты в нем располагаются в пяти областях: центр, север, юг, запад, восток. В момент расчета расположения преимущество имеют компоненты на севере и юге. После того, как эти компоненты размещены, layout определяет размещение компонентов на востоке и западе. И уже в последнюю очередь размещается компонент по центру, который занимает все оставшееся пространство. Попробуйте изменять размеры формы до такой степени, чтобы увидеть, кто будет иметь преимущество. Если уменьшить размер очень сильно, то можно увидеть, что в первую очередь «отнимается» пространство у центрального компонента, потом у левого и правого. И в последнюю очередь у нижнего компонента и верхнего. Данный layout достаточно точно отражает поведение многих программ – верхний toolbar, нижняя строка состояния, левая и правая панель навигации и инструментов и наконец центральная рабочая область.

GridLayout – думаю, что по названию многие могли догадаться, что данный layout располагает компоненты в гриде (таблице). Для примера я расположил двенадцать кнопок в таком вот гриде. Кроме количества ячеек Вы можете задавать отступы компонентов внутри ячейки. Задание таких границ продемонстрировано в примере.

CardLayout – размещает все компоненты как карты в колоде. В этом случае только один компонент, который в данный момент является верхним, будет показан на экране. Используя методы этого layout’а – first(), last(), next(), previous() и show() – программист имеет возможность переключаться между компонентами. Данный пример иллюстрирует эти возможности. Достаточно эффективно можно использовать CardLayout совместно с BorderLayout. CardLayout используется для центральной рабочей области, где может быть множество открытых документов, а BorderLayout создает «окружение».

GridBagLayout – вариант достаточно сложного управления размещением компонентов. В данном менеджере используются специальные правила, которые задаются при добавлении каждого компонента. При прорисовке именно эти правила определяют, как будет вести себя тот или иной компонент. Поэтому хотелось бы предварительно описать этот важный класс. Его название – GridBagConstraints. Рассмотрим подробно важные поля этого класса, а потом приведем пример использования:

gridx, gridy – как Вы уже догадались из названия данного менеджера, он фактически оперирует тоже с набором ячеек подобно GridLayout, только более гибко. Эти два поля определяют фактически ячейку, куда будет помещен лидирующий угол компонента. Как можно будет увидеть чуть ниже, компонент может занимать несколько ячеек, как по горизонтали, так и по вертикали. Лидирующий угол зависит от того, какую ориентацию имеет компонент. Ориентация зависит от языковых установок. Русский язык предусматривает написание слева направо. А арабский – справа налево. Для ориентации слева направо лидирующий угол – верхний левый. Для ориентации справа налево – верхний правый. Как Вы наверно догадались, сами ячейки также будут иметь разный порядок нумерации – справа налево и вниз или слева направо и вниз.
gridwidth, gridheight – эти поля определяют, сколько ячеек будет занимать компонент (по горизонтали и по вертикали соответственно) в ячейках.
fill – компонент может занимать как все отведенное ему пространство, так и не все — это зависит от его размера. Данное поле как раз предназначено для того, чтобы определить, как компонент будет занимать все отведенные для него ячейки. Всего определено четыре константы: NONE – компонент не будет покрывать все пространство, HORIZONTAL – компонент будет растянут на всю ширину, VERTICAL – компонент будет растянут на всю высоту, BOTH – компонент будет растянут на всю ширину и всю высоту.
ipadx, ipady – данные поля фактически определяют, сколько пикселей будет прибавлено к минимальному размеру компонента. Т.е. фактически компонент становится больше на 2*ipadx пикселей по горизонтали и на 2*ipady пикселей по вертикали.
insets – это поле выполняет функцию подобно ipadx и ipady, только оно определяет ширину границы между краем компонента и краем области, которую он будет занимать. Интересно отметить, что данное поле может иметь и отрицательное значение. В этом случае компонент будет как бы «вылезать» за границы своей области.
anchor – в том случае, если компонент несколько меньше области, в которой он располагается, он может фактически «прилипать» к разным сторонам или быть в центре. Для такого поведения определено достаточно много констант, и их значения можно посмотреть в описании класса GridBagConstraints. Константы описывают, как абсолютное поведение компонента в своей области, так и относительное, которое зависит от предыдущих компонентов и положения самого компонента на форме.
weightx, weighty – в принципе название отражает суть. Это «вес» компонента, который показывает, как будут распределяться компоненты. Чем выше вес у компонента, тем больше места он пытается занять при увеличении размера контейнера. Т.е. если один компонент имеет «вес» 0, а второй 1, то второй при увеличении формы будет занимать все доступное новое пространство, а первый останется прежнего размера. Если все компоненты имеют «вес» равный нулю (так оно и есть по умолчанию), то будет просто появляться дополнительное пространство между ними.

Я не стал сильно мудрить и привел пример из Java API – пример очень наглядный и Вы можете просто попробовать поиграть с разными значениями (я кое-где поставил комментарии для этого)

Также хотелось бы упомянуть возможность задания абсолютных координат без каких-либо layout вообще. Насколько этот вариант подходит – решать Вам. В примере можно видеть, что кнопки будут находиться на своих местах независимо от того, как меняются размеры окна.

А теперь давайте рассмотрим вариант создания нестандартного layout. Любой layout должен просто реализовать необходимые методы. Вот они:
— public void addLayoutComponent(String name, Component comp)
— public void removeLayoutComponent(Component comp)
— public Dimension minimumLayoutSize(Container parent)
— public Dimension preferredLayoutSize(Container parent)
— public void layoutContainer(Container parent)

 

Наиболее важным является последний метод. Он как раз и занимается тем, что «расставляет» все элементы в том порядке, в котором нам надо.
Я написал в качестве примера простой layout, который располагает свои элементы вдоль диагонали.

 

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.