В предыдущих главах мы размещали компоненты главным образом "вручную", задавая их размеры и положение в контейнере абсолютными координатами в координатной системе контейнера. Для этого мы применяли метод setBounds ().
Такой способ размещает компоненты с точностью до пиксела, но не позволяет перемещать их. При изменении размеров окна с помощью мыши компоненты останутся на своих местах привязанными к левому верхнему углу контейнера. Кроме того, нет гарантии, что все мониторы отобразят компоненты так, как вы задумали.
Чтобы учесть изменение размеров окна, надо задать размеры и положение компонента относительно размеров контейнера, например, так:
int w = getSize().width; // Получаем ширину
int h = getSize().height; // и высоту контейнера.
Button b = new Button("OK"); // Создаем кнопку.
b.setBounds(9*w/20, 4*h/5, w/10, h/10);
и при всяком изменении размеров окна задавать расположение компонента заново.
Чтобы избавить программиста РѕС‚ этой кропотливой работы, РІ библиотеку AWT внесены РґРІР° интерфейса: LayoutManager Рё порожденный РѕС‚ него интерфейс LayoutManager2, Р° также пять реализаций этих интерфейсов: классы BorlerLayout, CardLayout, FlowLayout, GridLayout Рё GridBagLayout. Рти классы названы менеджерами размещения (layout manager) компонентов. РњС‹ уже использовали некоторые РёР· РЅРёС… РІ предыдущих главах без РІСЃСЏРєРѕРіРѕ объяснения. Библиотека Swing добавляет Рє указанным классам СЃРІРѕРё менеджеры размещения, используемые контейнерами Swing.
Каждый программист может создать собственные менеджеры размещения, реализовав интерфейсы LayoutManager или LayoutManager2.
Посмотрим, как размещают компоненты эти классы.
Менеджер FlowLayout
Наиболее просто поступает менеджер размещения FlowLayout. Он укладывает в контейнер один компонент за другим слева направо как кирпичи, переходя от верхних рядов к нижним. При изменении размера контейнера "кирпичи" перестраиваются, как показано
на рис. 14.1. Компоненты поступают в том порядке, в каком они заданы в методах
add().
В каждом ряду компоненты могут прижиматься к левому краю, если в конструкторе аргумент align равен FlowLayout.LEFT, к правому краю, если этот аргумент FlowLayout.RIGHT, или собираться в середине ряда, если FlowLayout.CENTER.
Между компонентами можно оставить промежутки (gap) РїРѕ горизонтали hgap Рё вертикали vgap. Рто задается РІ конструкторе:
FlowLayout(int align, int hgap, int vgap);
Второй конструктор задает промежутки размером 5 пикселов:
FlowLayout(int align);
Третий конструктор определяет выравнивание по центру и промежутки 5 пикселов:
FlowLayout();
После формирования объекта эти параметры можно изменить методами:
setHgap(int hgap); setVgap(int vgap); setAlignment(int align);
В листинге 14.1 создаются кнопка JButton, метка JLabel, кнопка выбора JCheckBox, раскрывающийся список JComboBox, поле ввода JtextField и все это размещается в контейнере JFrame. Рисунок 14.1 содержит вид перечисленных компонентов при разных размерах контейнера.
Листинг 14.1. Менеджер размещения FlowLayout
import java.awt.*; import javax.swing.*;
class FlowTest extends JFrame{
FlowTest(String s){ super(s);
setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10));
add(new JButton("РљРЅРѕРїРєР°"));
add(new JLabel("Метка"));
add(new JCheckBox("Выбор"));
add(new JComboBox());
add(new JTextField("Р’РІРѕРґ", 10));
setSize(300, 100);
setVisible(true);
}
public static void main(String[] args){
JFrame f= new FlowTest(" Менеджер FlowLayout"); f.setDefaultCloseOperation(EXIT ON CLOSE);
}
Рис. 14.1. Размещение компонентов с помощью FlowLayout |
Менеджер BorderLayout
Менеджер размещения BorderLayout делит контейнер на пять неравных областей, полностью заполняя каждую область одним компонентом, как показано на рис. 14.2. Области получили географические названия — north, south, west, east и center.
Метод add () в случае применения BorderLayout имеет два аргумента: ссылку на компонент comp и область region, в которую помещается компонент — одну из перечисленных ранее констант: add(Component comp, String region).
Обычный метод add (Component comp) с одним аргументом помещает компонент в область
CENTER.
Ссылку на компонент, помещенный в определенную область, можно получить методом
getLayoutComponent(Object region);
параметром которого служит одна из перечисленных ранее констант.
В классе два конструктора:
□ BorderLayout () — между областями нет промежутков;
□ BorderLayout (int hgap int vgap) - между областями остаются горизонтальные hgap и
вертикальные vgap промежутки, задаваемые в пикселах.
Если в контейнер помещается менее пяти компонентов, то некоторые области не используются и не занимают места в контейнере, как можно заметить на рис. 14.3. Если не занята область center, то компоненты прижимаются к границам контейнера.
В листинге 14.2 создаются пять кнопок, размещаемых в контейнере. Обратите внимание на отсутствие установки менеджера в контейнере setLayout () — менеджер BorderLayout установлен в контейнере JFrame по умолчанию. Результат размещения показан на рис. 14.2.
Листинг 14.2. Менеджер размещения BorderLayout
import java.awt.*; import javax.swing.*;
class BorderTest extends JFrame{
BorderTest(String s){ super(s);
add(new JButton("North"), BorderLayout.NORTH); add(new JButton("South"), BorderLayout.SOUTH); add(new JButton("West"), BorderLayout.WEST); add(new JButton("East"), BorderLayout.EAST); add(new JButton("Center")); setSize(300, 200); setVisible(true);
}
public static void main(String[] args){
JFrame f= new BorderTest(" Менеджер BorderLayout"); f.setDefaultCloseOperation(EXIT ON CLOSE);
}
}
Рис. 14.2. Области размещения BorderLayout |
Рис. 14.3. Компоновка с помощью FlowLayout и BorderLayout |
Менеджер размещения BorderLayout кажется неудобным: он располагает не больше пяти компонентов, последние растекаются по всей области, области имеют странный вид. Но дело в том, что в каждую область можно поместить не компонент, а панель, и размещать компоненты на ней, как сделано в листинге 14.3 и показано на рис. 14.3. Напомним, что на панелях Panel и JPanel менеджер размещения по умолчанию —
FlowLayout.
Листинг 14.3. Сложная компоновка
import java.awt.*; import javax.swing.*;
class BorderPanelTest extends JFrame{
BorderPanelTest(String s){ super(s);
// Создаем панель p2 с тремя кнопками JPanel p2 = new JPanel();
p2.add(new JButton("Выполнить")); p2.add(new JButton("Отменить")); p2.add(new JButton("Выйти"));
JPanel p1 = new JPanel(); p1.setLayout(new BorderLayout());
// Помещаем панель p2 с кнопками на "юге" панели p1 p1.add(p2, BorderLayout.SOUTH);
// Поле ввода помещаем на "севере" p1.add(new JTextField("Поле ввода", 20), BorderLayout.NORTH);
// Область ввода помещается на панель с прокруткой JScrollPane sp = new JscrollPane(
new JTextArea("Область ввода", 5, 20));
// Панель прокрутки помещается в центр панели p1 p1.add(sp), BorderLayout.CENTER);
// Панель p1 помещаем в "центре" контейнера add(p1, BorderLayout.CENTER); setSize(300, 200); setVisible(true);
}
public static void main(String[] args){
JFrame f= new BorderPanelTest(" Сложная компоновка"); f.setDefaultCloseOperation(EXIT ON CLOSE);
}
}
Менеджер GridLayout
Менеджер размещения GridLayout расставляет компоненты в таблицу с заданным в конструкторе числом строк rows и столбцов columns:
GridLayout(int rows, int columns);
Все компоненты получают одинаковый размер. Промежутков между компонентами нет.
Второй конструктор позволяет задать промежутки между компонентами в пикселах по горизонтали hgap и вертикали vgap:
GridLayout(int rows, int columns, int hgap, int vgap);
Конструктор по умолчанию GridLayout () задает таблицу размером 0x0 без промежутков между компонентами. Компоненты будут располагаться в одной строке.
Компоненты размещаются менеджером GridLayout слева направо по строкам созданной таблицы в том порядке, в котором они заданы в методах add ().
Нулевое количество строк или столбцов означает, что менеджер сам создаст нужное их число.
В листинге 14.4 выстраиваются кнопки для калькулятора, а рис. 14.4 показывает, как выглядит это размещение.
Листинг 14.4. Менеджер GridLayout
import java.awt.*; import javax.swing.*; import java.util.*;
class GridTest extends JFrame{
GridTest(String s){ super(s);
setLayout(new GridLayout(4, 4, 5, 5));
StringTokenizer st = new StringTokenizer("7 8 9 / 4 5 6 * 1 2 3 — 0 . = +"); while(st.hasMoreTokens())
add(new JButton(st.nextToken())); setSize(200, 200); setVisible(true);
}
public static void main(String[] args){
JFrame f= new GridTest(" Менеджер GridLayout"); f.setDefaultCloseOperation(EXIT ON CLOSE);
}
}
Рис. 14.4. Размещение кнопок менеджером GridLayout |
Менеджер CardLayout
Менеджер размещения CardLayout своеобразен — РѕРЅ показывает РІ контейнере только РѕРґРёРЅ, первый (first), компонент. Остальные компоненты лежат РїРѕРґ первым РІ определенном РїРѕСЂСЏРґРєРµ как игральные карты РІ колоде. РС… расположение определяется РїРѕСЂСЏРґРєРѕРј, РІ котором написаны методы add(). Следующий компонент можно показать методом next(Container c), предыдущий — методом previous(Container c), последний — методом last(Container c), первый — методом first(Container c). Аргумент этих методов — ссылка РЅР° контейнер, РІ который помещены компоненты, обычно this.
В классе два конструктора:
□ CardLayout () — не отделяет компонент от границ контейнера;
□ CardLayout (int hgap, int vgap) — задает горизонтальные hgap и вертикальные vgap поля.
Менеджер CardLayout позволяет организовать и произвольный доступ к компонентам. Метод add () для менеджера CardLayout имеет своеобразный вид:
add(Component comp, Object constraints);
Здесь аргумент constraints должен иметь тип String и содержать имя компонента. Нужный компонент с именем name можно показать методом
show(Container parent, String name);
В листинге 14.5 менеджер размещения cl работает с панелью p, помещенной в "центр" контейнера JFrame. Панель p указывается как аргумент parent в методах next() и show(). На "север" контейнера JFrame отправлена панель p2 с меткой и раскрывающимся списком ch. Рисунок 14.5 демонстрирует результат работы программы.
Листинг 14.5. Менеджер CardLayout
import java.awt.*; import javax.swing.*;
class CardTest extends JFrame{ CardTest(String s){ super(s);
JPanel p = new JPanel();
CardLayout cl = new CardLayout(); p.setLayout(cl);
p.add(new JButton("Русская страница"),"page1"); p.add(new JButton("English page"), "page2"); p.add(new JButton("Deutsche Seite"), "page3"); add(p); cl.next(p); cl.show(p, "page1");
JPanel p2 = new JPanel(); p2.add(new JLabel("Выберите язык:"));
JComboBox ch = new JComboBox(); ch.addItem("Русский"); ch.addItem("Английский"); ch.addItem("Немецкий");
p2.add(ch);
add(p2, BorderLayout.NORTH);
setSize(400, 300); setVisible(true);
}
public static void main(String[] args){
JFrame f= new CardTest(" Менеджер CardLayout"); f.setDefaultCloseOperation(EXIT ON CLOSE);
}
}
Рис. 14.5. Менеджер размещения CardLayout |
Менеджер GridBagLayout
Менеджер размещения GridBagLayout расставляет компоненты наиболее гибко, позволяя задавать размеры и положение каждого компонента.
В классе GridBagLayout есть только один конструктор, конструктор по умолчанию, без аргументов. Менеджер класса GridBagLayout, в отличие от других менеджеров размещения, не содержит правил размещения. Он играет только организующую роль. Ему передаются ссылка на компонент и правила расположения этого компонента, а сам он помещает данный компонент по указанным правилам в контейнер. Все правила размещения компонентов задаются в объекте другого класса, GridBagConstraints.
Менеджер размещает компоненты в таблице с неопределенным заранее числом строк и столбцов. Один компонент может занимать несколько ячеек этой таблицы, заполнять ячейку целиком, располагаться в ее центре, углу или прижиматься к краю ячейки.
Класс GridBagConstraints содержит одиннадцать полей, определяющих размеры компонентов, РёС… положение РІ контейнере Рё взаимное положение, Рё несколько констант — значений некоторых полей. РћРЅРё перечислены РІ табл. 14.1. Рти данные определяются конструктором, имеющим одиннадцать параметров РїРѕ числу полей. Второй конструктор — конструктор РїРѕ умолчанию — присваивает параметрам значения, заданные РїРѕ умолчанию.
Таблица 14.1. Поля класса GridBagConstraints | |
Поле | Значение |
anchor | Направление размещения компонента в контейнере. Константы: абсолютные — CENTER , NORTH , EAST , NORTHEAST , SOUTHEAST , SOUTH , SOUTHWEST , WEST , NORTHWEST ; относительные — PAGE START , PAGE END , LINE START , LINE END , FIRST LINE START , FIRST LINE END , LAST LINE START , LAST LINE END , относительно базовой линии — BASELINE , BASELINE_LEADING , BASELINE_TRAILING , ABOVE_BASELINE , ABOVE_BASELINE_LEADING , ABOVE_BASELINE_TRAILING , BELOW_BASELINE , BELOW BASELINE LEADING , BELOW BASELINE TRAILING ; по умолчанию — CENTER |
fill | Растяжение компонента для заполнения ячейки. Константы: none, horizontal, vertical, both; по умолчанию — NONE |
gridheight | Количество ячеек в колонке, занимаемых компонентом. Целое типа int , по умолчанию 1. Константа remainder означает, что компонент займет остаток колонки, relative — будет следующим по порядку в колонке |
Таблица 14.1 (окончание) | |
Поле | Значение |
gridwidth | Количество ячеек в строке, занимаемых компонентом. Целое типа int , по умолчанию 1. Константа remainder означает, что компонент займет остаток строки, relative — будет следующим в строке по порядку |
gridx | Номер ячейки в строке. Самая левая ячейка имеет номер 0. По умолчанию константа relative , что означает: следующая по порядку |
gridy | Номер ячейки в столбце. Самая верхняя ячейка имеет номер 0. По умолчанию константа relative , что означает: следующая по порядку |
insets | Поля в контейнере. Объект класса Insets ; по умолчанию объект с нулями |
ipadx , ipady | Горизонтальные и вертикальные поля вокруг компонентов; по умолчанию 0, 0 |
weightx , weighty | Пропорциональное растяжение компонентов при изменении размера контейнера; по умолчанию 0, 0 |
Как правило, объект класса GridBagConstraints создается конструктором по умолчанию, затем значения нужных полей меняются простым присваиванием новых значений, например:
GridBagConstraints gbc = new GridBagConstraints(); gbc.weightx = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridheight = 2;
После создания объекта gbc класса GridBagConstraints менеджеру размещения указывается, что при помещении компонента comp в контейнер следует применять правила, занесенные в объект gbc.
Для этого применяется метод
add(Component comp, GridBagConstraints gbc);
Ртак, схема применения менеджера GridBagLayout такова:
GridBagLayout gbl = new GridBagLayout(); // Создаем менеджер. setLayout(gbl); // Устанавливаем его в контейнер.
// Задаем правила размещения по умолчанию GridBagConstraints c = new GridBagConstraints();
JButton b1 = c.gridwidth add(b1, c);
JButton b2 = c.gridwidth add(b2, c);
new JButton(); 2;
new JButton(); 1;
// Создаем компонент.
// Меняем правила размещения.
// Помещаем компонент b1 в контейнер // по указанным правилам размещения с. // Создаем следующий компонент.
// Меняем правила для его размещения. // Помещаем в контейнер.
Рё С‚. Рґ.
В документации к классу GridBagLayout приведен хороший пример использования этого менеджера размещения.
Контейнеры Swing
Поскольку класс JComponent библиотеки Swing — прямой наследник класса AWT Container, а компоненты Swing расширяют класс JComponent, все они являются контейнерами. Мы уже видели в предыдущих главах, что одни компоненты могут содержать другие компоненты. Но в библиотеке Swing есть и компоненты, специально предназначенные для размещения других компонентов. Некоторые используют специально разработанные для них менеджеры размещения. Сейчас мы дадим обзор таких контейнеров. Кроме того, в библиотеке Swing есть много готовых диалоговых окон, которые будут рассмотрены в конце этой главы.
Панель JPanel
Класс JPanel реализует простую невидимую панель для размещения компонентов. Он очень похож на панель класса Panel библиотеки AWT.
Конструктор по умолчанию JPanel () применяет к панели менеджер размещения компонентов FlowLayout. Напомним, что этот менеджер располагает компоненты рядами, укладывая их слева направо и сверху вниз как кирпичи в порядке обращения к методам add (), устанавливая при этом такой размер каждого компонента, который возвращает метод getPreferredSize () этого компонента. При изменении размера панели компоненты перестраиваются, увеличивая или уменьшая количество рядов. Если метод getPreferredSize () не определен, то компонент не будет виден на панели. В таком случае надо обратиться к методу setPreferredSize(Dimension) компонента и установить его подходящий размер.
Конструктор JPanel (LayoutManager) применяет Рє панели заданный менеджер размещения. Рто можно сделать Рё позднее методом setLayout(LayoutManager), унаследованным РѕС‚ класса Container.
Панель класса JPanel применяет двойную буферизацию (double buffering) для перерисовки своего содержимого. Описание метода двойной буферизации мы дадим в главе 20. Если двойная буферизация не нужна, то следует создать панель конструктором
JPanel(false).
Наконец, четвертый конструктор, JPanel(LayoutManager, boolean), задает менеджер размещения и применение двойной буферизации.
Как правило, применение панели ограничивается созданием ее экземпляра и размещением на ней компонентов унаследованными от класса Container методами:
□ add(Component comp) — добавляет компонент comp в конец списка компонентов, лежащих на панели;
□ add(Component comp, Object constraints) — добавляет компонент comp в конец списка компонентов, лежащих на панели, и передает менеджеру размещения параметры constraints, суть которых зависит от типа менеджера;
□ add (Component comp, int ind) - вставляет компонент comp в указанную позицию ind
списка компонентов панели;
□ add(Component comp, Object constraints, int ind) — содержит все эти параметры.
Панель прокрутки JScrollPane
Класс JScrollPane содержит РѕРґРёРЅ компонент, обеспечивая прокрутку его содержимого Рё снабжая РїСЂРё необходимости линейками прокрутки. Рто СѓРґРѕР±РЅРѕ для текстовой области JTextArea, для таблиц JTable, СЃРїРёСЃРєРѕРІ, изображений Рё РґСЂСѓРіРёС… компонентов, чье содержимое РЅРµ умещается РІ РѕРєРЅРµ компонента. Возможность прокрутки РЅРµ встроена РІ эти компоненты, чтобы можно было легко отказаться РѕС‚ нее РІ тех случаях, РєРѕРіРґР° содержимое компонента РЅРµ должно прокручиваться, РЅРѕ РѕРЅРё реализуют интерфейс Scrollable, описывающий методы предоставления информации линейкам прокрутки.
Компонент помещается на панель прокрутки сразу же при ее создании конструктором
JScrollPane(Component) или позднее методом setViewportView(Component). Полосы прокрутки РјРѕРіСѓС‚ всегда находиться РЅР° экране, появляться РїСЂРё необходимости или РЅРµ появляться вообще. Рто определяется методами:
void setVerticalScrollBarPolicy(int); void setHorizontalScrollBarPolicy(int);
Аргументом первого метода служит одна из констант класса JScrollPane:
в–Ў vertical_scrollbar_always;
в–Ў vertical_scrollbar_as_needed;
в–Ў VERTICAL_SCROLLBAR_NEVER,
а второго — одна из констант этого же класса:
в–Ў horizontal_scrollbar_always;
в–Ў horizontal_scrollbar_as_needed;
в–Ў HORIZ ONTAL_S CROLLBAR_NEVER.
Точнее говоря, эти и другие константы собраны в интерфейсе ScrollPaneConstants, реализованном классом JScrollPane.
Панель прокрутки имеет сложное строение. На самом деле кроме своего содержимого и двух полос прокрутки она может содержать еще шесть компонентов: заголовок, устанавливаемый методом setColumnHeaderView(Component), столбец слева, задаваемый методом setRowHeaderView (Component), и четыре компонента по углам, размещаемые методом setCorner (String, Component), применение которого можно посмотреть в листинге 14.6. Все это показано на рис. 14.6, который нарисован программой листинга 14.6. Размещением всех девяти компонентов занимается специально разработанный для этого менеджер размещения ScrollPaneLayout. Он жестко определяет место и размер каждого дополнительного компонента. К панели прокрутки, как ко всякому контейнеру, разрешается применить другой менеджер размещения методом setLayout(LayoutManager), но новый менеджер может быть только расширением менеджера размещения
ScrollPaneLayout.
Листинг 14.6. Компоненты панели прокрутки
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class ScrollComps extends JFrame{
ScrollComps(){
super(" Компоненты панели прокрутки"); setLayout(new FlowLayout());
JScrollPane sp = new JScrollPane(new JTextArea(5,30));
sp.setPreferredSize(new Dimension(200, 200));
sp.setCorner(JScrollPane.LOWER LEFT CORNER, new JLabel(" LL")); sp.setCorner(JScrollPane.LOWER RIGHT CORNER, new JLabel("LR")); sp.setCorner(JScrollPane.UPPER LEFT CORNER, new JLabel(" UL")); sp.setCorner(JScrollPane.UPPER RIGHT CORNER, new JLabel("UR"));
JLabel lh = new JLabel(" Header"); lh.setBorder(BorderFactory.createEtchedBorder()); sp.setColumnHeaderView(lh);
JLabel lr = new JLabel("Row");
lr.setBorder(BorderFactory.createEtchedBorder()); sp.setRowHeaderView(lr);
sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); sp.setViewportBorder(BorderFactory.createEtchedBorder());
add(sp);
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT ON CLOSE); setVisible(true);
}
public static void main(String[] args){ new ScrollComps();
}
}
Рис. 14.6. Компоненты панели прокрутки |
Видимая часть компонента, находящегося РЅР° панели прокрутки, Р° также заголовок Рё столбец слева представлены экземплярами класса JViewport. Задача этого класса — выбрать участок компонента Рё быстро показать его РІ "смотровом РѕРєРЅРµ" (viewport), Р° также обеспечить быструю Рё правильную прокрутку компонента. Поэтому компонент JViewport может содержать только РѕРґРёРЅ компонент, расположением которого занимается специально разработанный менеджер размещения viewportLayout. Ртот менеджер "растягивает" размещаемую область компонента РґРѕ размеров смотрового РѕРєРЅР°.
В последнее время большое распространение получила мышь с колесиком, с помощью которого удобно выполнять прокрутку. По умолчанию панель прокрутки предоставляет возможность прокрутки колесиком, но ее можно отключить методом
setWheelScrollingEnabled(false);
Проверить, допускает ли панель прокрутку колесиком мыши, можно логическим методом
public boolean isWheelScrollingEnabled();
Двойная панель JSplitPane
Панель класса JSplitPane содержит РґРІР° компонента, разделенных тонкой полосой, которую можно перемещать СЃ помощью мыши, меняя таким образом взаимные размеры компонентов. Компоненты РјРѕРіСѓС‚ располагаться РїРѕ горизонтали, что определяется константой horizontal_split класса JSplitPane, или РїРѕ вертикали — vertical_split. Рти константы указываются РІ конструкторе JSplitPane(int orientation). Конструктор РїРѕ умолчанию JSplitPane () задает горизонтальное расположение компонентов.
Панель JSplitPane РїСЂРё перемещении разделительной черты может перерисовывать компоненты сразу же РїРѕ мере передвижения или после окончательной установки разделительной черты. Рто определяется вторым параметром конструктора JSplitPane(int
orientation, boolean continuous).
Р’ перечисленных конструкторах РЅРµ задаются размещаемые компоненты. Вместо РЅРёС… конструктор создает Рё размещает РґРІРµ РєРЅРѕРїРєРё JButton СЃ надписями, возвращаемыми статическими методами UIManager.getString("SplitPane.leftButtonText") Рё UIManager.getString ("SplitPane. rightButtonText" ). Рто просто надписи "left button" Рё "right button", как показано РЅР° СЂРёСЃ. 14.7.
Четвертый конструктор, JSplitPane(int orientation, Component left, Component right), кроме расположения orientation сразу задает компонент, который будет располагаться слева (сверху) left, и тот, что будет располагаться справа (снизу) right.
Рис. 14.7. Двойная панель |
Очень часто компоненты, размещаемые на панели, — это панели прокрутки класса JScrollPane, содержащие текст, изображение, таблицу или другие компоненты.
Наконец, пятый конструктор задает все свойства:
JSplitPane(int orientation, boolean continuous, Component left, Component right).
Положение разделительной черты отмечается числом пикселов от левого (верхнего) края панели. Его можно получить методом getDividerLocation(), а установить из программы — методом setDividerLocation (int). В некоторых графических системах единица измерения может быть другой. В таком случае удобнее использовать метод setDividerLocation (double), задающий положение разделительной черты в процентах ширины (высоты) панели числом от 0.0 до 1.0.
Панель хранит и предыдущее положение разделительной черты. Его можно получить методом getLastDividerLocation ( ), а установить из программы методом
setLastDividerLocation(int).
Толщина разделительной черты назначается методом setDividerSize(int), параметр которого задается в пикселах. По умолчанию в Java L&F толщина равна 8 пикселов.
Разделительную черту нельзя переместить так, чтобы компонент стал меньше своего минимального размера, определенного методом getMinimumSize(). Границы ее перемещения определяются методами getMinimumDividerLocation() и getMaximumDividerLocation(). Однако можно поместить на разделительную черту две небольшие кнопки с треугольными стрелками методом setOneTouchExpandable(true). Они видны на рис. 14.7. При щелчке кнопкой мыши на одной из этих кнопок один компонент распахивается на всю панель, а другой исчезает полностью.
Компоненты можно установить на панель или заменить другими компонентами с помощью методов setLeftComponent(Component), setRightComponent(Component), setTopComponent(Component), setBottomComponent(Component), причем можно всегда пользоваться только первой или только последней парой методов независимо от фактического горизонтального или вертикального расположения компонентов.
Панель с вкладками JTabbedPane
Класс JTabbedPane создает сразу несколько панелей. На экране видна только одна из них, для остальных панелей показаны вкладки (tabs). Щелчок кнопкой мыши по вкладке вызывает на экран связанную с ней панель.
Конструктор по умолчанию JTabbedPane() создает одну пустую панель без вкладок. Конструктор JTabbedPane (int pos) задает расположение вкладок. Параметр этого конструктора pos — одна из констант класса JtabbedPane: top, bottom, left, right. Как правило, вкладки помещаются сверху (TOP), но, как видите, их можно поместить снизу, слева и справа.
Если все вкладки не помещаются в окно панели в один ряд, то они могут располагаться несколькими рядами или прокручиваться, для чего в строке вкладок появляются кнопки прокрутки, как показано на рис. 14.8. Первый метод расположения вкладок обозначается константой wrap_tab_layout, второй — константой scroll_tab_layout класса
JTabbedPane. Третий конструктор, JTabbedPane (int pos, int tab), задает своим вторым параметром один из этих двух методов.
Рис. 14.8. Панель с вкладками |
Как видите, конструкторы класса РЅРµ создают содержащиеся РІ нем панели Рё РЅРµ помещают РЅР° РЅРёС… компоненты. Рто выполняется после создания объекта класса JTabbedPane следующими методами:
□ Component add(Component) — добавляет компонент на последнюю панель и пишет на вкладке имя компонента;
□ Component add(String, Component) и void addTab(String, Component) — пишут на вкладке строку, записанную в первом параметре;
□ void add (Component, Object) - помещает на вкладку объект, определенный вторым
параметром. Обычно это изображение типа Icon;
□ Component add(Component, int) — вставляет компонент в указанную позицию;
□ void add (Component, Object, int) -объединяет возможности остальных методов;
□ void addTab (String, Icon, Component) — помещает на вкладку строку и/или изображение;
□ void addTab(String title, Icon image, Component comp, String tip) — последний параметр tip задает всплывающую подсказку.
Все эти методы так или иначе обращаются к основному методу
void insertTab(String title, Icon image, Component comp, String tip. int ind);
которым можно пользоваться во всех случаях.
Многочисленные методы setXxx () позволяют установить отдельные элементы панелей Рё вкладок. РљСЂРѕРјРµ того, можно задать цвет фона методом setBackgroundAt (Color), как показано РЅР° СЂРёСЃ. 14.8 Рё РІ листинге 14.7. Рто СѓРґРѕР±РЅРѕ для того, чтобы разметить вкладки разными цветами.
Листинг 14.7. Панель с разноцветными вкладками
import java.awt.*; import javax.swing.*;
public class Tabbed extends JFrame{
Tabbed(){
super(" Панель с вкладками"); setLayout(new FlowLayout());
String[] day = {"Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"};
JTabbedPane sp = new JTabbedPane(JTabbedPane.TOP,
JTabbedPane.SCROLL_TAB_LAYOUT); sp.setPreferredSize(new Dimension(300, 100)); for (int i = 0; i < 7; i++){
sp.add(day[i], new JLabel("Метка " + i)); sp.setBackgroundAt(i, new Color(16*i, 0, 16*(7-i)));
}
add(sp);
setSize(400, 400);
setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true) ;
}
public static void main(String[] args){ new Tabbed();
}
}
Линейная панель Box
Класс Box расставляет компоненты РІ РѕРґРЅСѓ строку или РІ РѕРґРёРЅ столбец, выравнивая РёС… ширину или высоту РїРѕ размеру наибольшего компонента. Ртот класс был разработан для создания панелей инструментальных РєРЅРѕРїРѕРє JToolBar, РЅРѕ его можно применять Рё для РґСЂСѓРіРёС… целей. Р’ классе есть только РѕРґРёРЅ конструктор — Box (int), РІ котором задается РѕРґРЅР° РёР· РґРІСѓС… констант класса BoxLayout: константа x_axis — размещение компонентов РІ РѕРґРЅСѓ строку, или y_axis — размещение компонентов РІ РѕРґРёРЅ столбец.
Еще один способ создания линейной панели — воспользоваться статическим методом
createHorizontalBox() или статическим методом createVerticalBox(). Рти методы всего лишь обращаются Рє конструктору СЃ соответствующей константой.
Сами компоненты добавляются к панели Box унаследованными от класса Container методами add(Component), add(Component, int).
Расположением компонентов в классе Box занимается специально разработанный менеджер размещения BoxLayout. Применить другой менеджер к этому классу нельзя, метод setLayout (LayoutManager) выбрасывает исключение, но менеджер BoxLayout может с успехом применяться в контейнерах иных типов. Рассмотрим его подробнее.
Менеджер размещения BoxLayout
Ркземпляры класса BoxLayout создаются конструктором BoxLayout(Container, int). Первым параметром указывается контейнер, размещением компонентов РІ котором будет управлять создаваемый менеджер размещения. Второй параметр задает СЃРїРѕСЃРѕР± расположения компонентов РѕРґРЅРѕР№ РёР· констант x_axis — расположение слева направо, y_axis — расположение сверху РІРЅРёР·, line_axis Рё page_axis — расположение определяется контейнером. Создание Рё применение менеджера выглядят примерно так:
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X AXIS)); p.add(new JLabel("Введите имя: ", JLabel.RIGHT)); p.add(new JTextField(30));
Если задано горизонтальное расположение компонентов, то менеджер пытается сделать высоту всех компонентов одинаковой, равной высоте самого высокого компонента. При вертикальном расположении менеджер старается выровнять ширину компонентов по самому широкому компоненту. Если это сделать не удается, например потому, что задан максимальный размер компонентов, то по умолчанию компоненты размещаются в центре панели. Точнее говоря, это зависит от того, какое значение возвращают методы getAlignmentx () и getAlignmentY () самого компонента. Возвращаемое этими методами значение меняется от 0.0f — компонент прижимается влево (вверх), до 1.0f — компонент прижимается вправо (вниз) относительно других компонентов.
Компоненты-заполнители
Казалось бы, в панели Box нет ничего хитрого, но ее возможности расширяются тем, что в число размещаемых на панели компонентов можно включить невидимые компоненты-заполнители трех видов.
Первый вид заполнителя — невидимая разделительная область (rigid area), имеющая фиксированные размеры. Она создается статическим методом
static Component Box.createRigidArea(Dimension);
и вставляется между компонентами, создавая промежуток фиксированного размера между ними.
Заполнитель второго вида — невидимая "распорка" (strut) — имеет только один фиксированный размер. У горизонтальной распорки, создаваемой статическим методом
static Component Box.createHorizontalStrut(int width);
фиксирована только ширина. При горизонтальном расположении компонентов распорку можно использовать для создания промежутков между компонентами, а при вертикальном расположении — для задания ширины всей панели.
У вертикальной распорки, создаваемой статическим методом
static Component Box.createVerticalStrut(int height);
фиксирована высота. Она используется аналогично горизонтальной распорке.
Третий РІРёРґ заполнителя — невидимая "надувная подушка" (glue), "раздуваясь", заполняет РІСЃРµ выделенное ей пространство, раздвигая остальные компоненты Рё прижимая РёС… Рє краям панели, если РѕРЅРё имеют фиксированный максимальный размер. Ртот заполнитель создается РѕРґРЅРёРј РёР· статических методов:
□ static Component Box.createGlue () — "подушка" раздувается во все стороны;
□ static Component Box.createHorizontalGlue() — "подушка" раздается в ширину;
□ static Component Box.createVerticalGlue() — "подушка" раздается в высоту.
Кроме этих трех компонентов-разделителей можно использовать невидимый компонент с фиксированным минимальным, максимальным и предпочтительным размерами. Он является объектом класса Filler, вложенного в класс Box, и создается конструктором
Box.Filler(Dimension min, Dimension pref, Dimension max);
Преимущество этого объекта в том, что он может поменять размеры методом
void changeShape(Dimension min, Dimension pref, Dimension max);
Листинг 14.8 показывает пример размещения текстовой области и двух кнопок на панели класса Box. Для того чтобы сдвинуть кнопки вправо, применена "подушка".
Листинг 14.8. Размещение компонентов на панели Box
import java.awt.*; import javax.swing.*;
public class MyBox extends JFrame{
JButton b1 = new JButton("Первая");
JButton b2 = new JButton("Вторая");
JTextArea ta = new JTextArea(5, 30);
MyBox(){
super(" Линейная панель"); setLayout(new FlowLayout());
Box out = Box.createVerticalBox();
Box ini = Box.createHorizontalBox();
Box in2 = Box.createHorizontalBox();
out.add(ini); out.add(in2);
ini.add(ta);
in2.add(Box.createHorizontalGlue());
in2.add(b1); in2.add(b2);
add(outer);
setSize(400, 400);
setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true);
}
public static void main(String[] args){ new MyBox();
}
}
Ртак, класс Box, использующий разделители, становится удобным Рё РіРёР±РєРёРј контейнером. Нужно еще учесть, что компоненты можно обвести рамкой необходимой ширины Рё то, что контейнеры класса Box РјРѕРіСѓС‚ вкладываться РґСЂСѓРі РІ РґСЂСѓРіР° РІ разных сочетаниях. Р’СЃРµ это делает класс Box вполне приемлемым контейнером для размещения самых разных компонентов, Р° РЅРµ только инструментальных РєРЅРѕРїРѕРє.
Менеджер размещения SpringLayout
Контейнер Box, управляемый менеджером размещения BoxLayout, оказался удобным средством компоновки компонентов, но для сложного размещения большого числа
компонентов приходится вкладывать экземпляры класса Box РґСЂСѓРі РІ РґСЂСѓРіР°. Рљ тому же возникает необходимость часто применять компоненты-разделители. Рто РїСЂРёРІРѕРґРёС‚ Рє неоправданной сложности РєРѕРјРїРѕРЅРѕРІРєРё.
Вообще говоря, возможности размещения компонентов в контейнерах графических библиотек AWT и Swing очень велики и изменяются в широком диапазоне.
РќР° РѕРґРЅРѕРј конце этого диапазона — абсолютное размещение, РїСЂРё котором РїСЂСЏРјРѕ указываются координаты (x, y), ширина width Рё высота height компонента РІ координатной системе контейнера. Рто выполняет метод
setBounds(int x, int y, int width, int height);
или пара методов
setLocation(int x, int y); setSize(int width, int height);
При этом компоненты совершенно точно помещаются в контейнер, но их положение и размеры не меняются при изменении размеров контейнера. Можно связать координаты и размеры компонента с размерами контейнера, например:
JPanel p = new JPanel(); p.setLayout(null);
int w = p.getSize().width, h = p.getSize().height;
JButton b = new JButton("Выход"); b.setBounds(w/10, h/10, w/5, h/8); p.add(b);
Рто сложно Рё требует долгой кропотливой РїРѕРґРіРѕРЅРєРё.
На другом конце диапазона — менеджер размещения FlowLayout, располагающий компоненты просто по их предпочтительному размеру, и менеджер GridLayout, подгоняющий размеры всех компонентов под размер контейнера.
В состав Java SE, начиная с версии JDK 1.4, введен новый менеджер размещения SpringLayout, пытающийся совместить точность и гибкость размещения компонентов. Для определения положения и размеров компонента этот менеджер пользуется координатами (x, y) и размерами width, height, но это не числа, а объекты специально разработанного небольшого класса Spring. Опишем этот класс.
Размеры Spring
Абстрактный класс Spring описывает объекты, хранящие размеры. Каждый объект хранит минимальный, предпочтительный Рё максимальный размеры. Рти размеры РјРѕРіСѓС‚ использоваться как размеры промежутков между компонентами. Поскольку класс Spring абстрактный, объект СЃ размерами задается РЅРµ конструктором, Р° статическим методом
public static Spring constant(int min, int pref, int max);
Второй статический метод, constant(int size), возвращает объект класса Spring с совпадающими между собой размерами, равными size.
Два статических метода берут координату height или координату width у минимального, предпочтительного и максимального размеров заданного компонента comp:
public static Spring height(Component comp); public static Spring width(Component comp);
Ртак, РЅР° объект класса Spring можно смотреть как РЅР° трехмерный вектор
(min, pref, max) .
Кроме этих трех размеров, объект хранит еще и текущее значение value, устанавливаемое методом setValue(int value). Значение value должно лежать между минимальным и максимальным значениями. Начальное значение value совпадает с предпочтительным размером.
Менеджер размещения получает эти размеры, обращаясь к методам getMinimumValue(),
getMaximumValue(), getPreferredValue(), getValue().
Очень часто менеджер размещения SpringLayout использует несколько объектов Spring. При этом их размеры складываются, вычитаются, берется наибольший или наименьший размер. Все операции выполняются, как операции с векторами, покоординатно. Для удобства их выполнения в класс Spring введены статические методы таких вычислений:
□ public static Spring max(Spring s1, Spring s2) — возвращает новый объект, размеры которого составлены из наибольших значений объектов s1 и s2;
□ public static Spring minus(Spring s) - возвращает новый объект, размеры которого
равны размерам объекта s с обратным знаком;
□ public static Spring sum(Spring s1, Spring s2) — возвращает новый объект, размеры которого равны сумме соответствующих размеров объектов s1 и s2.
Для вычисления минимального из двух значений s1 и s2 нет специального метода, оно вычисляется так:
Spring sp = Spring.minus(Spring.max(Spring.minus(s1), Spring.minus(s2)));
Промежутки Constraints
Объект класса Spring — всего лишь четверка чисел. Он не может определить пространство в контейнере, а используется только для построения объекта вложенного класса
SpringLayout.Constraints.
Объект класса Constraints, подобно прямоугольнику, содержит координаты (x, y), ширину width и высоту height, но эти величины — не числа, а объекты класса Spring. Объекты x и y — не жестко фиксированные координаты левого верхнего угла, как в прямоугольнике. Они имеют наименьшее, наибольшее, предпочтительное и текущее значения, которыми пользуется менеджер размещения SpringLayout. Он варьирует положение левого верхнего угла компонента в заданных объектами x и y пределах. Поэтому они обозначаются статическими строковыми константами WEST и NORTH класса SpringLayout. Ширина width и высота height — это наименьшая, наибольшая, предпочтительная и текущая ширина и высота компонента в контейнере, управляемом менеджером размещения SpringLayout. Чаще всего они совпадают с соответствующими значениями самого компонента. Величины x + width и y + height обозначаются статическими строковыми константами east и south и определяют положение правого нижнего угла компонента.
Для получения и установки всех этих значений в классе Constraints есть методы-"сеттеры" и "геттеры": setX(Spring), getX(), setY(Spring), getY(), setWidth(Spring), getWidth(), setHeight(Spring), getHeight(). Методы setConstraint(String, Spring) и getConstraint (String) устанавливают и выдают объект класса Spring по заданному имени
NORTH, WEST, SOUTH или EAST.
Размещение компонентов
После обсуждения этих вспомогательных классов можно объяснить принцип работы менеджера размещения SpringLayout на примере.
Допустим, мы хотим расположить несколько компонентов comp[0], comp [1], comp [2] и т. д. в одну строку с фиксированными промежутками между ними величиной в 6 пикселов. Кроме того, мы решили оставить промежутки в 10 пикселов от границ контейнера. Листинг 14.9 содержит программу, выполняющую такое размещение, а рис. 14.9 показывает результат размещения.
Листинг 14.9. Размещение компонентов SpringLayout
import java.awt.*; import javax.swing.*;
public class SpringWin extends JFrame{
JComponent[] comp = {
new JButton("Длинная надпись"),
new JButton("Надпись с^> двумя строками"),
new JButton("OK")
};
public SpringWin(){
super(" Размещение SpringLayout");
SpringLayout sl = new SpringLayout(); setLayout(sl);
// Задаем величину промежутка между компонентами Spring xPad = Spring.constant(6);
// Задаем величину отступа от границ контейнера Spring yPad = Spring.constant(10);
// Текущее положение левого верхнего угла Spring currX = yPad;
// Наибольшая высота компонента, пока 0 Spring maxHeight = Spring.constant(0);
for (int i = 0; i < comp.length; i++){ add(comp[i]);
// Получаем размер i-го компонента SpringLayout.Constraints cons = sl.getConstraints(comp[i]);
// Устанавливаем положение i-го компонента cons.setX(currX); cons.setY(yPad);
// Перемещаем текущее положение угла currX = Spring.sum(xPad, cons.getConstraint("East"));
/ / Рзменяем наибольшую высоту
maxHeight = Spring.max(maxHeight, cons.getConstraint("South"));
}
// Получаем размеры контейнера SpringLayout.Constraints pCons = sl.getConstraints(c);
// Устанавливаем размеры всего содержимого контейнера pCons.setConstraint(SpringLayout.EAST, Spring.sum(currX, yPad)); pCons.setConstraint(SpringLayout.SOUTH, Spring.sum(maxHeight, yPad));
pack();
setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true);
}
public static void main(String args[]){ new SpringWin();
}
}
Рис. 14.9. Размещение SpringLayout |
Панель инструментальных кнопок JToolBar
Класс JToolBar создает панели инструментальных кнопок. Обычно такая панель занимает строку ниже строки меню или столбец слева. Очень часто панель делают плавающей — ее можно перемещать по экрану — или всплывающей.
Пустая горизонтальная панель создается конструктором JToolBar ().
Конструктор JToolBar (int) задает расположение панели: горизонтальное — константа horizontal, вертикальное — константа vertical.
Конструктор JToolBar(string) определяет заголовок горизонтальной панели.
Наконец, конструктор JToolBar(string, int) определяет заголовок и расположение панели.
Документация Java SE рекомендует управлять контейнером, в который помещают панель инструментов, с помощью менеджера размещения BorderLayout и ничего не помещать в граничные области этого контейнера. В этом случае панель чаще всего помещают на "север". Слева (сверху) панели имеется полоса с "насечкой". Она видна на рис. 14.10. Наведя курсор мыши на эту полосу, панель можно перемещать по контейнеру. При перенесении панели на "запад", "восток" или на "юг", она занимает эту область, располагая свои компоненты по вертикали или по горизонтали. При перенесении панели в "центр" или вынесении ее за окно контейнера, панель автоматически оформляется в отдельное окно класса JFrame. В строке заголовка отдельного окна появляется строка, заданная в конструкторе. Полоса с "насечкой" сохраняется в этом окне, с ее помощью можно вернуть панель на прежнее место. Панель возвращается на свое первоначальное место и при закрытии ее окна.
Панель инструментов можно сделать неперемещаемой методом setFloatable(false). Полоска с "насечкой" исчезает, панель нельзя передвигать по экрану.
Обычно инструментальные кнопки на панели обведены тонкой рамкой, как на Панели 2 рис. 14.10, но после применения метода setRollover(true) рамка будет появляться только при наведении курсора мыши на кнопку.
Р РёСЃ. 14.10. Рнструментальные панели |
Для расположения компонентов класс JToolBar применяет свой внутренний менеджер размещения DefaultToolBarLayout, основанный на менеджере BoxLayout, следовательно, панель инструментов может использовать свойства этого менеджера размещения. Листинг 14.10 дает пример создания панели инструментов.
Листинг 14.10. Панели инструментальных кнопок
import java.awt.*; import javax.swing.*;
public class MyTool extends JFrame{
MyTool(){
super(" Рнструментальные панели");
JToolBar tb1 = new JToolBar(" Панель 1"), tb2 = new JToolBar(" Панель 2");
tb1.setRollover(true);
tb1.add(new JButton(new ImageIcon("Add24.gif"))); tb1.add(new JButton(new ImageIcon("AlignTop24.gif"))); tb1.add(new JButton(new ImageIcon("About24.gif")));
tb2.add(new JButton("Первая")); tb2.add(new JButton("Вторая")); tb2.add(new JButton("Третья"));
add(tb1, Bo rde rLayout.NORTH); add(tb2, Bo rde rLayout.WEST);
setSize(400, 400);
setDefaultCloseOperation(EXIT ON CLOSE);
setVisible(true);
}
public static void main(String[] args){ new MyTool();
}
}
В составе Java SE в каталоге $JAVA_HOME/demo/jfc/Notepad/ есть пример текстового редактора с панелью инструментальных кнопок класса JToolBar. Его можно запустить, перейдя в этот каталог и набрав в командной строке
java -jar Notepad.jar
РќР° панель инструментов можно поместить любой компонент методом add(Component), РЅРѕ, как правило, РЅР° ней располагаются РєРЅРѕРїРєРё СЃ ярлычками. Рти РєРЅРѕРїРєРё дублируют некоторые, чаще всего используемые, пункты меню. Для того чтобы облегчить СЃРІСЏР·СЊ РєРЅРѕРїРѕРє Рё пунктов меню СЃ РёС… действиями, РІ библиотеке Swing разработан интерфейс Action.
Рнтерфейс Action
Рнтерфейс Action разработан для того, чтобы собрать РІ РѕРґРЅРѕРј месте РІСЃРµ, относящееся Рє какому-то действию: командную клавишу, клавишу-ускоритель, изображение-ярлык, строку описания РІ пункте меню, всплывающую подсказку.
Он расширяет интерфейс ActionListener, добавляя к его единственному методу
actionPerformed (ActionEvent) несколько статических полей класса String- имен опреде
ляемых интерфейсом объектов — и методы определения этих полей putValue(string
key, Object value), getValue(String key).
Рнтерфейс описывает объекты СЃ такими именами:
□ ACCELERATOR_KEY-имя клавиши-ускорителя, объекта класса Keystroke;
□ ACTION_COMMAND_KEY имя командной клавиши класса KeyMap;
□ default — строка значений по умолчанию;
□ displayed_mnemonic_index_key — целое число, индекс действия;
□ large_icon_key — имя изображения;
□ long_description — описание действия для всплывающей справки;
□ mnemonic_key — код командной клавиши типа int;
□ name — имя действия, записываемое в пункт меню;
□ selected_key — выбранное значение;
□ short_description — краткое описание действия для всплывающей подсказки;
□ small_icon — имя изображения на инструментальной кнопке.
Поля определяются, например, так:
act.putValue(Action.SMALL ICON, new ImageIcon("save.gif"));
и используются потом так:
ImageIcon ic = (Imagelcon)act.getValue(Action.SMALL ICON);
Объект, реализующий интерфейс Action, может быть доступен (enabled) или недоступен (disabled). Рто регулируется методом setEnabled(boolean). Например, РїСЂРё создании текстового редактора команды Вырезать, Копировать следует сделать недоступными, РїРѕРєР° РЅРµ выделен текст РІ РѕРєРЅРµ редактирования.
Рнтерфейс Action частично реализован абстрактным классом AbstractAction, РІ котором РЅРµ определен только метод actionPerformed(ActionEvent). Достаточно расширить класс AbstractAction, определив этот метод, Рё можно использовать его возможности.
Некоторые контейнеры, в число которых входят JMenu, JPopupMenu и JToolBar, умеют использовать объекты, реализующие интерфейс Action. Достаточно обратиться к методу add (Action act) такого контейнера, и он создаст соответствующий компонент со свойствами, определенными в объекте act.
Например, метод tb.add(act) панели инструментов tb класса JToolBar создаст инструментальную кнопку класса JButton с изображением, командной клавишей, всплывающей подсказкой и прочими свойствами инструментальной кнопки, содержащимися в объекте act. Метод m.add(act) меню m класса JMenu с тем же объектом act создаст пункт меню класса JMenultem с надписью, ярлычком, всплывающей подсказкой, взятыми у того же объекта act.
Контейнер автоматически присоединит к созданному компоненту обработчик события
ActionEvent, описанный в методе actionPerformed (ActionEvent). Кроме того, контейнер будет автоматически отслеживать изменения в самом объекте типа Action и приводить созданный компонент в соответствие с этими изменениями.
Классы, реализующие интерфейс Action, очень удобно использовать в тех случаях, когда одно и то же действие выполняется несколькими элементами графического интерфейса. Например, сохранение файла может быть вызвано пунктом меню Сохранить, инструментальной кнопкой с изображением дискеты или из всплывающего контекстного меню. В любом случае сохранение файла выполняет один объект типа Action, присоединенный к этим графическим элементам их методом add(Action) .
Слоеная панель JLayeredPane
Слоеная панель (layered pane) — это экземпляр класса JLayeredPane. Она состоит из множества лежащих друг на друге слоев, в которых располагаются компоненты. Компоненты, лежащие в верхних слоях, визуально перекрывают компоненты, находящиеся в нижних слоях. Слои на панели нумеруются целыми числами, представленными объектами класса Integer. Слой, номер которого больше, располагается выше слоя с меньшим номером. Можно рассматривать слои как третью координату z на экране — глубину.
Метод add(Component comp, Object constraints) класса Container переопределен в классе JLayeredPane так, что второй параметр задает слой, в который помещается компонент. Например, компонент comp можно поместить в слой с номером 50 методом add(comp, new Integer(50)).
Шесть слоев обозначены статическими константами типа Integer. Они интенсивно используются методами самой библиотеки Swing.
□ frame_content_layer — слой с номером Integer(-30000). Такой маленький номер гарантирует, что этот слой окажется ниже всех слоев. Данный слой используется классом JRootPane для размещения компонентов и строки меню.
□ default_layer — слой с номером Integer(0). Стандартная панель для размещения компонентов.
□ palette_layer — слой с номером Integer(i00). В нем обычно располагаются плавающие панели инструментальных кнопок и палитры.
□ modal_layer — слой с номером Integer(200). Здесь располагаются модальные диалоговые окна.
□ popup_layer — слой с номером Integer (300). Сюда помещают окна, всплывающие над модальными диалоговыми окнами.
□ drag_layer — слой с номером Integer(400). Сюда переводится компонент на время его перетаскивания с помощью мыши. После перетаскивания и отпускания кнопки мыши компонент погружается в свой слой.
Слоеная панель не управляется никаким менеджером размещения, размеры и положение компонентов на ней следует задавать унаследованным методом
setBounds(int x, int y, int width, int height);
или парой методов
setLocation(int x, int y); setSize(int width, int height);
Класс JLayeredPane расширяет класс JComponent и является компонентом Swing. Каждый слой ведет себя как обычный контейнер класса Container, но компоненты в нем могут перекрываться, причем компонент с меньшим номером перекрывает компонент с большим номером, но компонент с номером -1 лежит под всеми другими компонентами этого слоя.
Компоненты можно перемещать в своем слое методами:
□ moveToFront (Component comp) переместить компонент comp в позицию с номером 0;
□ moveToBack(Component comp) переместить компонент comp в позицию с номером -1;
□ setPosition(Component comp, int ind) — переместить компонент comp в позицию ind.
Чтобы поместить компонент в другой слой, надо сначала указать ему новый слой методами:
□ setLayer(Component comp, int layer) — указать компоненту comp слой с номером layer и позицию -1 в новом слое;
□ setLayer(Component comp, int layer, int pos) — указать компоненту comp слой layer и позицию pos в новом слое.
После этого надо поместить компонент в новый слой методом add ().
Слоеная панель обычно не используется напрямую. Она содержится в корневой панели класса JRootPane наряду с другими панелями.
Корневая панель JRootPane
Класс JRootPane определяет корневую панель (root pane), которая располагается в окнах
JWindow, JDialog, JFrame, JInternalFrame, JApplet, но может использоваться и в других контейнерах, реализующих интерфейс RootPaneContainer.
Корневая панель сама содержит несколько панелей размером во все окно, наложенных друг на друга. Нельзя просто положить компонент на корневую панель. Его надо положить на одну из панелей, содержащихся в корневой панели.
Ниже всех панелей лежит панель содержимого (content pane), которую можно получить методом getContentPane ( ). Рто контейнер класса Container, РІ котором обычно размещается большинство компонентов Рё строка меню. Управляет РёС… расположением РїРѕ умолчанию менеджер размещения BorderLayout. Чтобы заменить менеджер размещения панели содержимого, надо вызвать ссылку РЅР° нее следующим образом:
getContentPane().setLayout(new FlowLayout());
Таким же образом надо помещать компоненты на панель содержимого, например:
Container c = getContentPane();
c.add(new JLabel("0KHO регистрации", JLabel.CENTER), BorderLayout.NORTH); c.add(new JTextArea(5, 50));
Начиная с пятой версии Java SE, панель содержимого сделана панелью по умолчанию. Приведенные ранее строки теперь не требуют указания ссылки на контейнер c, можно написать просто
add(new JLabel("0KHO регистрации", JLabel.CENTER), BorderLayout.NORTH); add(new JTextArea(5, 50));
Панель содержимого располагается в нижнем слое frame_content_layer слоеной панели класса JLayeredPane. Кроме панели содержимого в этом же слое, в его верхней части, может находиться необязательная строка меню класса JMenuBar.
Ртак, корневая панель JRootPane РЅРµ содержит панель содержимого непосредственно. РћРЅР° хранит экземпляр класса JLayeredPane, который Рё помещает панель содержимого РІ СЃРІРѕР№ нижний слой.
Компоненты можно помещать в различные слои слоеной панели, получив ссылку на нее:
getLayeredPane().add(toolBar, JLayeredPane.PALETTE LAYER);
На самом верху корневой панели, выше слоеной панели, лежит невидимая "прозрачная панель” (glass pane). На самом деле это не панель, а экземпляр класса Component, следовательно, на нее нельзя поместить компоненты. Она служит, главным образом, для обработки событий мыши.
Дело РІ том, что обычно действия мыши обрабатываются компонентом, над которым расположен ее РєСѓСЂСЃРѕСЂ, точнее, обработчиком событий мыши MouseEvent, присоединенным Рє этому компоненту. Такой обработчик можно присоединить Рє прозрачной панели Рё обрабатывать события мыши одинаково РЅР° всей корневой панели, независимо РѕС‚ того, над каким компонентом расположен РєСѓСЂСЃРѕСЂ мыши. Рто можно сделать, например, так:
getGlassPane().addMouselnputListener(this);
Кроме того, прозрачная панель удобна для рисования. Линии и фигуры, нарисованные на ней, будут видны поверх всех компонентов, свободно пересекая их границы. По умолчанию прозрачная панель невидима. Для того чтобы рисунки, сделанные на ней, были видны, надо обратиться к методу setVisible(true).
Всеми панелями корневой панели распоряжается специально разработанный менеджер размещения. Его замена может привести к нарушению взаимодействия компонентов, находящихся на корневой панели. Но всегда можно создать новый экземпляр панели содержимого, слоеной панели или прозрачной панели и поместить его на корневую панель методами setContentPane(Container), setLayeredPane(JLayeredPane) и setGlassPane(Component) .
Очень часто разработчика не устраивает то, что панель содержимого — это простой контейнер библиотеки AWT, экземпляр класса Container. Ее можно легко заменить панелью другого типа, например:
JFrame fr = new JFrame("0KHO верхнего уровня");
JPanel c = new JPanel(); c.add(new JTextField(50)); c.add(new JButton("OK")); fr.setContentPane(c);
Обычно окно, в котором расположена корневая панель, оформляется по правилам текущего оконного менеджера графической оболочки операционной системы. Но метод setwindowDecorationStyle (int) позволяет задать другой стиль оформления. Аргумент этого метода может принимать одно из значений none (по умолчанию), frame, plain_dialog, IN FORMAT I ON_DIALOG, ERROR_DIALOG, COLOR_CHOOSER_DIALOG, FILE_CHOOSER_DIALOG, QUESTI ON_DIALOG,
warning_dialog. Подробнее о стилях оформления Look and Feel написано в главе 17.
РћРєРЅРѕ JWindow
Класс Jwindow представляет простейшее РѕРєРЅРѕ верхнего СѓСЂРѕРІРЅСЏ, которое может располагаться РІ любом месте экрана. Класс Jwindow расширяет класс window, применяемый РІ библиотеке AWT. Рто РѕРґРёРЅ РёР· четырех "тяжелых" компонентов библиотеки Swing. Возможности РѕРєРЅР° класса JWindow невелики. РЈ него нет рамки, строки заголовка СЃ кнопками. РћРЅРѕ РЅРµ регистрируется Сѓ РѕРєРѕРЅРЅРѕРіРѕ менеджера операционной системы, следовательно, РЅРµ перемещается РїРѕ экрану Рё РЅРµ изменяет СЃРІРѕРё размеры. Чаще всего РѕРєРЅРѕ класса JWindow используют как предварительное РѕРєРЅРѕ (splash window), появляющееся РЅР° экране РЅР° время загрузки РѕСЃРЅРѕРІРЅРѕРіРѕ РѕРєРЅР° приложения.
Окно JWindow может быть связано с уже существующим, "родительским" (parent) окном. Для этого его надо создать конструктором JWindow(Frame), JWindow(Window) или JWindow (Window, GraphicsConfiguration). На такое окно можно передать фокус ввода и, например, вводить текст в поле ввода, находящееся в окне, передав затем введенный текст родительскому окну. Окно располагается сверху родительского окна.
Если окно создано конструктором JWindow() или JWindow(GraphicsConfiguration), то оно не связано с родительским окном. На него нельзя передать фокус ввода, следовательно, в нем нельзя ничего сделать. Оно может скрываться под другими окнами.
Окно JWindow содержит непосредственно всего один компонент — корневую панель класса JRootPane. На эту корневую панель и кладутся все компоненты, как описано в предыдущем пункте. Можно получить ссылку на корневую панель методом getRootPane (), но в классе JWindow есть методы прямого доступа к панели содержимого
getContentPane ( ), слоеной панели getLayeredPane () и к прозрачной панели getGlassPane (). Разумеется, эти методы обращаются к соответствующим методам корневой панели. Вот, например, исходный код одного из этих методов: public Container getContentPane(){
return getRootPane().getContentPane();
}
Окно, как и всякий контейнер, наследует метод setLayout(LayoutManager), но замена менеджера размещения может привести к разрушению структуры окна. Поэтому метод setLayout () переопределен так, что он проверяет значение флага — защищенного логического поля rootPaneCheckingEnabled- и только если значение этого поля false, меняет
менеджер размещения. По умолчанию значение этого поля true, изменить его можно методом setRootPaneCheckingEnabled(boolean). Данный метод защищен (protected), он предназначен для использования при расширении класса JWindow.
Такое же правило действует при попытке добавить компонент унаследованными методами add ( ), addImpl ( ) непосредственно в окно JWindow, минуя находящийся в нем объект класса JRootPane.
Тем не менее всегда можно заменить всю корневую панель методом setRootPane(JRootPane) или ее панели методами setContentPane(Container), setLayeredPane(JLayeredPane) и setGlassPane(Component).
Унаследованный от класса Window метод dispose() уничтожает окно, освобождая все занятые им ресурсы.
Диалоговое окно JDialog
Класс JDialog расширяет класс Dialog библиотеки AWT (СЃРј. главу 10) Рё является "тяжелым" компонентом. РћРЅ создает модальные (modal) или немодальные диалоговые РѕРєРЅР°. РР· модального РѕРєРЅР° нельзя удалить фокус РІРІРѕРґР°, РЅРµ проделав РІСЃРµ находящиеся РІ нем действия.
Каждое диалоговое окно обязательно связано с родительским окном класса Window, Dialog или Frame. Даже конструктор по умолчанию JDialog () создает скрытое родительское окно.
Конструкторы JDialog(Frame), JDialog(Frame, String), JDialog(Dialog), JDialog(Dialog, String) JDialog (Window), JDialog(Window, String) создают немодальные диалоговые окна с заголовком или без заголовка.
Конструкторы JDialog(Frame, boolean), JDialog(Frame, String, boolean), JDialog(Dialog, boolean), JDialog(Dialog, String, boolean) создают модальные диалоговые окна типа модальности DEFAULT_MODALITY_TYPE, если последний параметр равен true, с заголовком или без заголовка.
Конструкторы JDialog(Window, Dialog.ModalityType), JDialog(Window, String,
Dialog.ModalityType) создают диалоговые окна с заданной модальностью.
Модальность окна и его заголовок можно изменить унаследованными методами
setModalityType(Dialog.ModalityType) Рё setTitle(String).
Диалоговое окно, как и окно JWindow, непосредственно содержит только один компонент — корневую панель JRootPane — и точно так же дает непосредственный доступ к панелям корневой панели методами getContentPane ( ), getLayeredPane (), getGlassPane () и к самой корневой панели методом getRootPane ( ).
Все компоненты следует помещать на панели, расположенные в корневой панели. Относительно помещения компонентов непосредственно в диалоговое окно применяется та же политика, что и для окна JWindow.
Так же как и для окна JWindow, для диалогового окна JDialog можно подготовить другие экземпляры панелей и установить их методами setRootPane(JRootPane), setContentPane(Container), setLayeredPane(JLayeredPane) и setGlassPane(Component).
Диалоговое окно снабжено рамкой и строкой заголовка, в которую помещается строка, записанная в конструкторе. В строке заголовка есть кнопка Закрыть, реакцию на которую, а заодно и реакцию на нажатие комбинации клавиш
setDefaultCloseOperation(int);
Реакция задается одной из трех констант:
□ do_nothing_on_close — отсутствие всякой реакции;
□ hide_on_close — окно становится невидимым (по умолчанию);
□ dispose_on_close — окно ликвидируется, освобождая оперативную память.
Если разработчик хочет задать какую-нибудь другую реакцию на попытку закрыть окно, то ему сначала надо отключить стандартную реакцию, например:
setDefaultCloseOperation(JDialog.DO_NOTHUNG_ON_CLOSE); addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){ ta.setText(tf.getText()); dispose();
}
});
По умолчанию диалоговое окно может изменять свои размеры, но это правило можно поменять унаследованным методом setResizable (boolean).
По умолчанию диалоговое окно появляется в рамке, со строкой заголовка, оформленными по правилам графической оболочки операционной системы. Данное оформление можно убрать методом setUndecorated(true), но вместе с этим будет потеряна и стандартная реакция на действия мыши с элементами оформления. После применения этого метода можно установить оформление текущего Look and Feel методом setWindowDecorationstyle(int) класса JRootPane. Подробно о Look and Feel написано в главе 17.
Очень часто диалоговые окна создаются для вывода сообщений, предупреждений, для подтверждения или отмены каких-то действий. В библиотеке Swing в классе JOptionPane собрана богатая коллекция готовых диалоговых окон. Речь о них пойдет немного позднее.
Окно верхнего уровня JFrame
Класс JFrame расширяет класс Frame графической библиотеки AWT. Рто полноценное самостоятельное РѕРєРЅРѕ верхнего СѓСЂРѕРІРЅСЏ, снабженное рамкой Рё строкой заголовка СЃ кнопками системного меню Свернуть, Развернуть Рё Закрыть, как принято РІ графической оболочке операционной системы.
Конструкторы класса JFrame ( ), JFrame (String) создают невидимое окно с заголовком или без заголовка. Чтобы вывести его на экран, надо воспользоваться методом
setVisible(true).
Окно JFrame непосредственно содержит только один компонент — корневую панель класса JRootPane. К нему относится все, что сказано в предыдущих разделах, за исключением модальности и родительского окна.
Реакция РЅР° щелчок РєРЅРѕРїРєРѕР№ мыши РїРѕ РєРЅРѕРїРєРµ закрытия РѕРєРЅР° тоже определяется методом setDefaultcloseOperation (int), РЅРѕ параметр может принять еще РѕРґРЅРѕ, четвертое значение: EXIT_ON_CLOSE завершить работу приложения методом System.exit(O). Рто значение РЅРµ следует применять РІ апплетах.
Напомним еще, что окно JFrame наследует от класса Frame возможность заменить ярлычок кнопки системного меню — дымящуюся чашечку кофе — другим ярлычком методом setIconImage (Image).
Как и в диалоговых окнах, можно убрать оформление окна, выполненное по правилам оконного менеджера графической оболочки операционной системы, методом setundecorated (true), установив затем оформление текущего Look and Feel методом
getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
Подробнее об этом написано в главе 17.
Внутреннее окно JInternalFrame
Класс JInternalFrame создает окно, очень похожее на окно класса JFrame, но существующее только внутри другого окна, обычно окна класса JDesktopPane. Его можно перемещать, менять размеры, сворачивать и разворачивать, но все это можно делать, не выходя за пределы объемлющего окна.
Поскольку внутреннее окно не зависит от операционной системы, а создается полностью средствами Java, оно получает по умолчанию Java L&F. В отличие от окна JFrame программа сама может управлять окном класса JInternalFrame: внутреннему окну можно разрешить или запретить менять размеры, сворачиваться в ярлык и разворачиваться на все объемлющее окно, закрываться. По умолчанию все эти четыре свойства отсутствуют. У внутреннего окна, созданного конструктором по умолчанию JInternalFrame (), отсутствуют кнопки Свернуть, Развернуть, Закрыть, при установке курсора мыши на границу окна курсор не меняет свой вид и не позволяет менять размеры окна, заголовок отсутствует. Кроме того, окно по умолчанию невидимо.
Возможности изменения окна устанавливаются конструкторами класса или методами
setClosable(boolean), setTitle(String), setlconifiable(boolean), setMaximizable(boolean), setResizable(boolean), setVisible(boolean).
Основной конструктор класса регулирует все эти возможности:
JInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable)
У остальных конструкторов отсутствует один или несколько параметров, отсутствующие параметры получают значение false. На рис. 14.11 показаны два внутренних окна, созданные разными конструкторами. Первое окно сдвинуто влево вниз, оно частично
обрезано границами внешнего окна. В листинге 14.11 приведена программа, создающая эти окна.
Листинг 14.11. Внутренние окна
import java.awt.*; import javax.swing.*;
public class IntFrame extends JFrame{
IntFrame(){
super(" Окно с внутренними окнами"); setLayout(new FlowLayout());
JInternalFrame ifrl =
new JInternalFrame(" Первое РѕРєРЅРѕ", true, true, true, true); ifr1.getContentPane().add(new JLabel(" Рто первое внутреннее РѕРєРЅРѕ")); ifrl.setPreferredSize(new Dimension(200, 200)); ifrl.setVisible(true);
add(ifrl);
JInternalFrame ifr2 = new JInternalFrame(" Второе окно"); ifr2.getContentPane().add(new JButtonC^TO второе внутреннее окно")); ifr2.setPreferredSize(new Dimension(200, 200)); ifr2.setVisible(true);
add(ifr2);
setSize(400, 400);
setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true);
}
public static void main(String[] args){ new IntFrame();
}
}
Рис. 14.11. Внутренние окна |
Как Рвсе окна Swing, внутреннее окно JInternalFrame содержит всего один компонент — корневую панель JRootPane — и обладает всеми методами работы с ней, перечисленными в предыдущих разделах.
К внутреннему окну можно применить все методы окна JFrame, за исключением остановки JVM — метод setDefaultcloseOperation (int) не принимает параметр EXIT_ON_CLOSE.
Рабочий стол JDesktopPane
Хотя внутренние окна можно поместить в любой контейнер, удобнее всего расположить их в специально разработанном внутреннем "рабочем столе" JDesktopPane. На нем размещаются окна верхнего уровня подобно тому, как на экране располагаются окна приложений.
Класс JDesktopPane расширяет класс JLayeredPane, следовательно, имеет множество слоев, благодаря чему компоненты могут перекрываться, но не управляется никаким менеджером размещения. Поэтому позицию и размеры компонента следует задавать методом setBounds (), как показано в листинге 14.12. На рис. 14.12 представлен вывод программы листинга 14.12.
Листинг 14.12. Внутренние окна на внутреннем рабочем столе
import java.awt.*; import javax.swing.*;
public class Desk extends JFrame{
Desk(){
super(" Внутренний рабочий стол");
JDesktopPane dp = new JDesktopPane(); setContentPane(dp);
JInternalFrame ifrl =
new JInternalFrame(" Первое РѕРєРЅРѕ", true, true, true, true); ifr1.getContentPane().add(new JLabel(" Рто первое внутреннее РѕРєРЅРѕ")); ifrl.setBounds(l0,l0, 200,200); ifrl.setVisible(true);
dp.add(ifrl);
JInternalFrame ifr2 = new JInternalFrame(" Второе окно"); ifr2.getContentPane().add(new JButtonC^TO второе внутреннее окно")); ifr2.setBounds(l50, 200, 200, l00); ifr2.setVisible(true);
dp.add(ifr2);
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT ON CLOSE); setVisible(true);
public static void main(String[] args){ new Desk();
}
}
Рис. 14.12. Внутренний рабочий стол |
Перемещение внутреннего окна внутри содержащего его контейнера можно ускорить, если заменить перерисовку всего окна во время перемещения перерисовкой только рамки методом
setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
Стандартные диалоги JOptionPane
Хотя класс JDialog позволяет создавать любые диалоговые окна, в подавляющем большинстве случаев их назначение сводится к выводу сообщений (message), подтверждению или отмене каких-то действий (confirm) и вводу коротких сведений (input).
Класс JOptionPane предоставляет более двадцати статических методов для создания модальных диалоговых РѕРєРѕРЅ. Рто три метода showMessageDialog ( ) СЃ разными аргументами, создающие РѕРєРЅР° сообщений, четыре метода showConfirmDialog(), формирующие РѕРєРЅР° подтверждения, шесть методов showinputDialog(), создающие РѕРєРЅР° РІРІРѕРґР°, Рё РѕРґРёРЅ метод, создающий диалоговое РѕРєРЅРѕ общего РІРёРґР° — showOptionDialog (). Перечисленные методы создают диалоговые РѕРєРЅР° класса JDialog. Еще более десяти методов РІРёРґР° showinternalXxxDialog () предназначено для формирования внутренних диалоговых РѕРєРѕРЅ класса JInternalFrame.
Окна сообщений, в свою очередь, бывают нескольких типов, снабжаемых определенными ярлыками и обозначаемых следующими константами:
□ in format Ion_mes sage — просто сообщение, в Java L&F это синий круг с буквой "i" внутри, как на рис. 14.20 (по умолчанию);
□ warning_message — предупреждение, желтый треугольник с восклицательным знаком внутри, как на рис. 14.15;
□ error_message — сообщение об ошибке, красный шестиугольник с "кирпичом" внутри, как на рис. 14.13;
□ question_message — вопрос, зеленый квадрат с вопросительным знаком внутри, как на рис. 14.14;
□ plain_message — произвольное сообщение без определенного ярлыка.
Сообщение любого типа можно снабдить произвольным ярлыком типа Icon, как РЅР° СЂРёСЃ. 14.16. Рто делается самым развитым РёР· данной РіСЂСѓРїРїС‹ методов — статическим методом
static void showMessageDialog(Component parent, Object message,
String title, int type, Icon icon);
Для работы указанного метода задается родительское окно parent, строка заголовка title, сообщение message, его тип type — одна из констант, перечисленных ранее, и ярлык icon.
Как видите, сообщение message задается объектом самого общего типа Object. В качестве сообщения может появиться компонент класса Component, изображение типа Icon. Все остальные объекты преобразуются в строку методом toString(), строка помещается в созданный объект класса JLabel, который и выводится в окно сообщения. Параметром message может быть и массив типа Object []. В этом случае в окно будет выведено несколько сообщений.
На рис. 14.13 показано окно сообщения, созданное методом
JOptionPane.showMessageDialog(this," В поле \"Код\" могут быть только цифры."," Ошибка", JOptionPane.ERROR MESSAGE); |
Рис. 14.13. Окно сообщения типа "Ошибка" |
Рис. 14.14. Окно подтверждения типа "Вопрос" |
РћРєРЅРѕ подтверждения или отмены действий содержит РґРІРµ или три РєРЅРѕРїРєРё: Yes (Да), No (Нет), Cancel (Отмена). Рто обозначается константами yes_no_option или YES_NO_CANCEL_OPTION Рё регулируется параметром optType методов showConfirmDialog ( ). Сигнатура метода этого типа СЃ самым большим числом параметров выглядит так:
static int showConfirmDialog(Component parent, Object message,
String title, int optType, int messType, Icon icon);
Метод возвращает одну из констант yes_option, no_option, cancel_option в зависимости от того, какая кнопка была нажата. При закрытии окна без всякого выбора возвращается значение closed_option. На рис. 14.14 показано окно подтверждения, используемое, например, так: int n = JOptionPane.showConfirmDialog(this,
"Сохранить этот/предыдущий вариант (Yes/No)?",
" Сохранение документа", JOptionPane.YES NO CANCEL OPTION,
JOptionPane.QUESTION_MESSAGE); switch(n){
case JOptionPane.YES OPTION: saveDoc(); break;
case JOptionPane.NO OPTION: restore(); saveDoc(); break;
case JOptionPane.CANCEL_OPTION:
case JOptionPane.CLOSED OPTION: break;
default:
}
Диалоговое окно ввода содержит поле для ввода краткого ответа, возвращаемого методом, или список выбора, а также кнопки OK и Cancel (Отмена). На рис. 14.15 показано окно, созданное методом
String s = (String)JOptionPane.showlnputDialog(this,
" Запишите ответ: ", " Ответ", JOptionPane.WARNING MESSAGE);
Рис. 14.15. Окно ввода типа "Предупреждение" |
Рис. 14.16. Окно ввода с вариантами ответа |
На рис. 14.16 показано окно, созданное методами
String[] vars = {"Первый", "Второй", "Третий"};
String s = (String)JOptionPane.showlnputDialog(this, "Выберите вариант ответа:", " Варианты ответа", JOptionPane.QUESTION MESSAGE, new ImageIcon("bird.gif"), vars, "Второй");
Для российских программистов, вечно озабоченных русификацией своих приложений, удобнее четвертый тип стандартных диалоговых окон, создаваемый методом
static int showOptionDialog(Component parent, Object message,
String title, int optType, int messType, Icon icon,
Object[] options, Object init);
Предпоследний параметр options задает надписи на кнопках диалогового окна или графические компоненты, выводимые в окно вместо кнопок. Последний параметр init выделяет одну из кнопок или графических компонентов.
Например, окно, показанное на рис. 14.14, будет лучше выглядеть, если его создать методами
String[] vars = {"Ртот", "Предыдущий", "РќРµ сохранять"};
int n = JOptionPane.showOptionDialog(this,
" Сохранить этот или предыдущий вариант?",
" Сохранение документа", JOptionPane.YES NO CANCEL OPTION,
JOptionPane.QUESTION_MESSAGE, null, vars, "Ртот");
как показано на рис. 14.17.
Рис. 14.17. Окно с русскими надписями |
Рис. 14.18. Простейшее диалоговое окно |
Как РІРёРґРЅРѕ РёР· СЂРёСЃСѓРЅРєРѕРІ, каждое стандартное диалоговое РѕРєРЅРѕ содержит элементы: предопределенный выбранным L&F или собственный ярлык, сообщение, РєРЅРѕРїРєРё Рё, может быть, поле РІРІРѕРґР°. Если такое строение диалогового РѕРєРЅР° РЅРµ устраивает разработчика, то РѕРЅ может создать собственное диалоговое РѕРєРЅРѕ класса JDialog, РІ которое поместить диалоговую панель JOptionPane. Для этого имеется семь конструкторов. Конструктор РїРѕ умолчанию JOptionPane () создает диалоговую панель СЃ РєРЅРѕРїРєРѕР№ OK Рё стандартной строкой сообщения. РћРЅР° показана РЅР° СЂРёСЃ. 14.18. Ртот СЂРёСЃСѓРЅРѕРє создан методами
JOptionPane op = new JOptionPane();
JDialog d = op.createDialog(this, " Простейшее диалоговое окно"); d.setVisible(true);
Конструктор с наибольшим числом параметров выглядит так:
JOptionPane(Object message, int messType, int optType,
Icon icon, Object[] options, Object init);
у остальных конструкторов приняты значения по умолчанию отсутствующих параметров.
На рис. 14.19 представлено окно, созданное методами
String[] opts = {"Применить", "Отменить", "Перейти", "Завершить"};
JOptionPane op = new JOptionPane(
"
JOptionPane.QUE STION_ME S SAGE,
JOptionPane.YES_NO_CANCEL_OPTION, null, opts, opts[2]);
JDialog d = op.createDialog(this, " Собственное диалоговое окно"); d.setVisible(true);
Окно с индикатором ProgressMonitor
Еще один вид диалоговых окон, предназначенный для слежения за протеканием какого-нибудь процесса, предоставляет класс ProgressMonitor. Окно этого класса показывает сообщение, индикатор-"градусник" — объект класса JProgressBar — и кнопки OK и Cancel.
Единственный конструктор класса
ProgressMonitor(Component parent, Object message, String note, int min, int max);
РєСЂРѕРјРµ ссылки parent РЅР° родительское РѕРєРЅРѕ, сообщения message, наименьшего min Рё наибольшего max значений "градусника" содержит параметр note. Рто строка, значение которой можно менять РІРѕ время ожидания методом setNote ( String).
Для смены значения индикатора выполняемый процесс должен обращаться Рє методу setProgress (int pos), задавая РІ нем текущее значение pos, лежащее между значением min Рё значением max. Рто похоже РЅР° работу СЃ классом JProgressBar, описанным РІ главе 11.
В листинге 14.13 приведен пример использования окна индикатора. Для изменения значения индикатора запущен простейший подпроцесс. Рисунок 14.20 показывает вывод программы листинга 14.13.
Листинг 14.13. Создание окна индикатора
import java.awt.*; import javax.swing.*;
public class Progress extends JFrame{
Progress(){
super(" Progress...");
final ProgressMonitor mon = new ProgressMonitor(this, "Рдет процесс.", "Осталось ", 0, 100);
Runnable runnable = new Runnable(){
public void run(){
for (int i = 1; i < 100; i++){ try{
mon.setNote( "Осталось " + (100 — i) + " %"); mon.setProgress(i);
if (mon.isCanceled()){ mon.setProgress(100); break;
}
Thread.sleep(100);
}catch(InterruptedException e){}
}
mon.close();
}
};
Thread thread = new Thread(runnable); thread.start();
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT ON CLOSE); setVisible(true);
}
public static void main(String[] args){ new Progress();
}
} В заключение нужно сказать, что следить за загрузкой большого входного потока класса Inputstream удобно с помощью специально разработанного фильтра входного потока — класса ProgressMonitorInputStream, расширяющего класс FilterInputStream.
Заключение
Все менеджеры размещения написаны полностью на языке Java, в состав Sun Java SE входят их исходные тексты. Если вы решили написать свой менеджер размещения, реализовав интерфейс LayoutManager или LayoutManager2, то посмотрите эти исходные тексты.
Вопросы для самопроверки
1. Что такое менеджер размещения?
2. Почему менеджеры размещения удобнее абсолютной расстановки компонентов?
3. В каких контейнерах можно установить менеджер размещения?
4. В каких компонентах можно установить менеджер размещения?
5. Почему менеджер размещения BorderLayout столь популярен?
6. Какой менеджер размещения установлен по умолчанию в окне класса JFrame?
7. Какой менеджер размещения установлен по умолчанию в классе JPanel?
8. Какой менеджер размещения установлен по умолчанию в классе JScrollPane?
9. Какой менеджер размещения установлен по умолчанию в классе JWindow?
10. Какой менеджер размещения установлен по умолчанию в классе JDialog?
11. Можно ли написать свой собственный менеджер размещения?
ГЛАВА 15
Рис. 14.19. Собственное диалоговое окно
Рис. 14.20. Окно индикатора