Материал: Портянкин И. Swing

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Искусство расположения

205

Для этого мы расчертим наш интерфейс линиями так, чтобы компоненты, имеющие одинаковые позиции по вертикали или горизонтали, выстраивались вдоль этих линий (рис. 7.5). Тогда нам не составит труда определить, как построить интерфейс в программе.

Вход в систему

Имя:

Пароль:

ОК Отмена

Рис. 7.5. Схема диалогового окна для входа в систему

«Легко сказать — расчертите линиями!» — заявите вы: «Чем при этом следует руководствоваться в первую очередь?» Это верно, но рецептов в таких случаях, как правило, не существует. В случае использования блочного подхода можно принять во внимание следующее:

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

Так как менеджер BoxLayout разделяет свободное пространство поровну между всеми компонентами, которые могут «расти» (мы обсудили это в разделе о заполнителях), нужно тщательно продумать, куда будет «уходить» свободное место.

Необходимо помнить о выравнивании компонентов по осям.

Очень часто достаточно просто взглянуть на набросок интерфейса, чтобы увидеть возможность применения того или иного менеджера расположения, особенно это касается групп компонентов одинаковых размеров (сразу появляется работа для табличного расположения GridLayout). Однако помните, как неаккуратно работают простые менеджеры с расстоянием между компонентами, и если с ними начнутся проблемы, обычно можно получить тот же результат, прибегнув к блочному расположению. А трудности с блочным расположением практически всегда сводятся к несогласованному выравниванию компонентов по осям, но для нас это не проблема.

Что же, с помощью рисунка 7.5 легко увидеть, какие менеджеры расположения нам могут помочь. Учитывая соображения о расширении текстовых полей в ширину, интерфейс построим, основываясь на горизонтальных «полосах». Для них выберем блочное расположение по оси X.

Поклонники последовательного расположения FlowLayout могут сказать, что оно позволит создать эти полосы еще проще, чем блочное. Сперва кажется, что это действительно так, но стоит вспомнить о некоторых хитростях в расположении FlowLayout: при

206

ГЛАВА 7

уменьшении окна текстовые поля могут оказаться под надписями, так как FlowLayout переносит компоненты на другие строки, если им не хватает места. Кроме того, если впоследствии понадобится дополнить интерфейс и использовать разные расстояния между компонентами, с расположением FlowLayout возникнут трудности, в то время как блочное расположение позволит свободно наращивать и изменять интерфейс.

Итак, расстояние зададим распорками, а размеры надписей сделаем одинаковыми вручную. Как видно из рисунка 7.5, выравнивание должно быть центральным. А вот группа кнопок нами уже создавалась с помощью пары из табличного и последовательного расположения с выравниванием по правому краю. Эту идею используем и здесь. (Кстати, в качестве нехитрого упражнения можете реализовать эту же «полосу» с помощью одной только панели с блочным расположением.) Для получения окончательного результата все созданные горизонтальные панели уложим друг на друга с помощью менеджера вертикального блочного расположения. В таком случае эти панели необходимо согласованно выровнять по левую сторону оси.

Осталось только разработать набор инструментов, который позволил бы нам при создании пользовательского интерфейса не переписывать раз за разом одни и те же фрагменты кода, придающие компонентам одинаковые размеры и располагающие их в соответствие с некоторыми рекомендациями Sun. Это будет класс с набором статических методов:

//com/porty/swing/GUITools.java

//Набор инструментов для окончательной

//шлифовки и придания блеска интерфейсу package com.porty.swing;

import javax.swing.*; import java.awt.*;

public class GUITools {

//инструмент для придания группе компонентов

//одинаковых размеров (минимальных,

//предпочтительных и максимальных).

public static void makeSameSize(JComponent... cs) {

//определение максимального размера

Dimension maxSize = cs[0].getPreferredSize(); for (JComponent c: cs) {

if ( c.getPreferredSize().width > maxSize.width ) { maxSize = c.getPreferredSize();

}

}

//придание одинаковых размеров

for (JComponent c : cs) { c.setPreferredSize(maxSize); c.setMinimumSize(maxSize); c.setMaximumSize(maxSize);

}

Искусство расположения

207

}

//позволяет исправить оплошность в

//размерах текстового поля JTextField

public static void fixTextFieldSize(JTextField field) { Dimension size = field.getPreferredSize();

//чтобы текстовое поле по-прежнему могло

//увеличивать свой размер в длину size.width = field.getMaximumSize().width;

//теперь текстовое поле не станет выше

//своей оптимальной высоты

field.setMaximumSize(size);

}

}

Первый метод самый полезный: в любом интерфейсе найдутся компоненты, которые нужно сделать одинаковыми. Заметьте, что makeSameSize() берет за основу ширину компонентов — определяет наиболее широкий компонент и выравнивает остальные по нему. Надо сказать, что в большинстве ситуаций выравнивание размеров компонентов происходит именно по ширине. Если вдруг вам понадобится метод для выравнивания по высоте, надо будет просто немного модифицировать этот метод и определять максимальный компонент как компонент с наибольшей высотой. Выравниваются все три размера компонентов. Обычно для компонентов, размеры которых специально делаются одинаковыми (кнопки, надписи, флажки, ползунки), это является наилучшим вариантом. Более сложные компоненты, которые при изменении окна должны определенным образом менять свои размеры (таблицы, текстовые компоненты, и т. п.) хорошо управляются с помощью подобранных нужным образом менеджеров расположения.

О назначении метода fixTextFieldSize() мы еще не говорили, но без него наше диалоговое окно может стать просто безобразным. Дело в том, что при появлении дополнительного пространства в окне текстовое поле JTextField увеличивается не только в длину, как ему и положено, но и в ширину, что совсем не вяжется с представлением об однострочном поле ввода. Это поведение не подходит для блочного расположения BoxLayout. Видимо, это связано с тем, что все текстовые компоненты в Swing унаследованы от базового класса JTextComponent, который и задает такие размеры, более подходящие для многострочных полей ввода и мини-редакторов. Чтобы исправить такую досадную оплошность, в классе GUITools и появился этот метод. Он оставляет длину текстового поля максимально возможной, а высоту заставляет оставаться на оптимальном уровне (который соответствует высоте текста).

Теперь, с классами BoxLayoutUtils и GUITools, все готово для того, чтобы в коде реализовать пользовательский интерфейс нашего диалогового окна:

//LoginDialog.java

//Этапы создание первоклассного

//пользовательского интерфейса на примере

//диалогового окна входа в систему import javax.swing.*;

import java.awt.*;

import com.porty.swing.BoxLayoutUtils; import com.porty.swing.GUITools;

208

ГЛАВА 7

public class LoginDialog extends JDialog { public LoginDialog(JFrame parent) {

super(parent, "Вход в систему");

//удаление окна при закрытии setDefaultCloseOperation(DISPOSE_ON_CLOSE);

//добавляем расположение в центр окна add(createGUI());

//задаем предпочтительный размер

pack();

// выводим окно на экран setVisible(true);

}

//этот метод будет возвращать панель с

//созданным расположением

private JPanel createGUI() {

//1. Создается панель, которая будет содержать

//все остальные элементы и панели расположения

JPanel main = BoxLayoutUtils.createVerticalPanel();

//Чтобы интерфейс отвечал требованиям Java,

//необходимо отделить его содержимое от

//границ окна на 12 пикселов.

//Для этого используем пустую рамку main.setBorder(

BorderFactory.createEmptyBorder(12,12,12,12));

//2. Поочередно создаются "полосы", на которые

//был разбит интерфейс на этапе анализа

//а) первое текстовое поле и надпись к нему

JPanel name = BoxLayoutUtils.createHorizontalPanel();

JLabel nameLabel = new JLabel("Имя:"); name.add(nameLabel); name.add(BoxLayoutUtils.createHorizontalStrut(12)); JTextField nameField = new JTextField(15); name.add(nameField);

//б) второе текстовое поле и надпись к нему

JPanel password = BoxLayoutUtils.createHorizontalPanel();

JLabel passwrdLabel = new JLabel("Пароль:"); password.add(passwrdLabel);

Искусство расположения

209

password.add(BoxLayoutUtils.createHorizontalStrut(12)); JTextField passwrdField = new JTextField(15); password.add(passwrdField);

// в) ряд кнопок

JPanel flow = new JPanel( new FlowLayout( FlowLayout.RIGHT, 0, 0) );

JPanel grid = new JPanel( new GridLayout( 1,2,5,0) );

JButton ok = new JButton("OK");

JButton cancel = new JButton("Отмена"); grid.add(ok);

grid.add(cancel); flow.add(grid);

//3. Проводятся необходимые действия по

//выравниванию компонентов, уточнению их

//размеров, приданию одинаковых размеров

//а) согласованное выравнивание

//вложенных панелей

BoxLayoutUtils.setGroupAlignmentX( Component.LEFT_ALIGNMENT, name, password, main, flow);

//б) центральное выравнивание надписей

//и текстовых полей

BoxLayoutUtils.setGroupAlignmentY( Component.CENTER_ALIGNMENT,

nameField, passwrdField, nameLabel, passwrdLabel);

//в) одинаковые размеры надписей к текстовым полям

GUITools.makeSameSize(nameLabel, passwrdLabel);

//д) устранение "бесконечной" высоты текстовых полей

GUITools.fixTextFieldSize(nameField); GUITools.fixTextFieldSize(passwrdField);

//4. Окончательный "сбор" полос в интерфейс main.add(name); main.add(BoxLayoutUtils.createVerticalStrut(12)); main.add(password); main.add(BoxLayoutUtils.createVerticalStrut(17)); main.add(flow);

//готово

return main;

}

// тестовый метод для проверки диалогового окна

Источник: https://studfile.net/preview/15935977/