Занятие 9
Основные визуальные компоненты Swing
Класс JComponent
Все визуальные компоненты библиотеки Swing унаследованы от класса JComponent
. Сам этот класс является абстрактными и непосредственно не используется, но все визуальные компоненты наследуют его методы. Рассмотрим наиболее полезные из них.
setEnabled(boolean enabled)
используется для управления активностью компонента. При вызове этого метода с параметром false компонент переходит в неактивное состояние. Для каждого наследника JComponent
эта «неактивность» может быть переопределена по-разному. Например, неактивная кнопка не нажимается, не реагирует на наводящуюся мышь и отображается монохромным серым цветом. Метод isEnabled()
возвращает true, если элемент активен и false в противном случае.
setVisible(boolean visible)
управляет видимостью компонента. Мы уже использовали его для отображения окна JFrame
. Большинство элементов управления, в отличие от окна, по умолчанию являются видимыми (поэтому мы не вызывали данный метод после создания кнопок в примерах предыдущей главы). Метод isVisible()
возвращает false, если элемент невидим и true в противном случае.
С помощью метода setBackground(Color color)
можно изменить цвет заднего фона компонента. Однако эффект будет иметь место лишь в том случае, если компонент непрозрачен (некоторые компоненты, например метка JLabel
по умолчанию являются прозрачными). Непрозрачность устанавливается методом setOpaque(boolean opaque)
с параметром true. Методы getBackground()
и isOpaque()
возвращают текущий цвет заднего фона и непрозрачность компонента.
Метка JLabel
В большинстве визуальных библиотек метка — один из самых простейших компонентов. Она представляет собой обычный текст, который выводится в заданном месте окна и используется для вывода вспомогательной текстовой информации: подписи к другим элементам, инструкции и предупреждения для пользователя. В Swing метка позволяет достичь более интересных эффектов. Во-первых, помимо текста можно использовать значок. Во-вторых, с ее помощью можно выводить отформатированный текст.
Текст и значок метки можно задать в ее конструкторе. У нее есть несколько конструкторов с различными параметрами, в частности:
JLabel(String text)
— создает метку с надписью text
JLabel(Icon image)
— создает метку со значком image
JLabel(String text, Icon image, int align)
— создает метку с надписью text
и значком image
. Третий параметр задает выравнивание текста вместе со значком. В качестве него может быть использована одна из констант, описанных в интерфейсе SwingConstants:
LEFT
, RIGHT
, CENTER
.
Для примера создадим окно с меткой, созданной при помощи третьего конструктора. Как и на прошлом занятии, мы будем использовать два класса, один из которых назовем SimpleWindow
и унаследуем его от класса окна JFrame
. В его конструкторе будут создаваться и размещаться все элементы окна. Второй класс будет создавать это окно и отображать его на экране (код будет таким же, как в примерах предыдущей главы).
Напишем в конструкторе класса SimpleWindow
следующий код:
SimpleWindow(){
super("Окно с надписью");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JLabel label = new JLabel("Метка со значком и с надписью", new ImageIcon("1.gif"), SwingConstants.RIGHT);
getContentPane().add(label);
pack();
}
Чтобы убедиться, что выравнивание по правому краю работает, необходимо немного растянуть окно, чтобы ширина метки стала больше оптимальной.
В библиотеке Swing метка (и не только она) может быть настроена для отображения отформатированного текста в формате HTML. Для этого необходимо, чтобы строка, устанавливаемая в качестве надписи метки, начиналась с тега <html>. После этого можно использовать в строке любый теги языка HTML версии 3.2, и они будут преобразовываться в соответствующие атрибуты форматирования. В этом легко убедиться, изменив в предыдущем примере строку с вызовом конструктора на:
JLabel label = new JLabel("<html>К этой метке применено " +
"HTML-форматирование, включая: <ul><li> <i>курсив</i>," +
"<li><b>полужирный</b> <li><font size = +2> увеличение размера </font>" +
"<li>маркированный список </ul>");
Поскольку текст нашей надписи достаточно длинный, строка для удобства восприятия разбивается на части и используется оператор +.
Перечислим основные методы класса JLabel
:
getText()
— возвращает текущий текст надписи метки
setText(String text)
— задает новый текст надписи
getIcon()
— возвращает значок метки
setIcon(Icon image)
— устанавливает новый значок. В качестве значка обычно используется объект уже знакомого нам простого класса ImageIcon
(как в вышеприведенном примере).
getVerticalAlignment()
, setVerticalAlignment(int align)
, getHorizontalAlignment()
, setHorizontalAlignment(int align)
— эти четыре метода позволяют получить текущее или установить новое выравнивание (по горизонтали и вертикали) метки относительно ее границ. Возможные положения описаны в интерфейсе SwingConstants
.
getVerticalTextPosition()
, setVerticalTextPosition(int align)
, getHorizontalTextPosition()
, setHorizontalTextPosition(int align)
— эти четыре метода позволяют получить текущее или установить новое выравнивание текста относительно значка. Возможные положения описаны в интерфейсе SwingConstants
.
getIconTextGap()
, setIconTextGap(int gap)
— позволяет получить или задать расстояние между текстом и значком метки в пикселах.
Кнопка JButton
Мы постоянно использовали кнопки в предыдущей главе, хотя и не касались возможностей их настройки. Кнопка — это прямоугольник с текстом (и/или значком), по которому пользователь щелкает, когда хочет выполнить какое-то действие (или о чем-то сигнализировать).
Кнопка создается одним из пяти конструкторов, в частности JButton()
, JButton(String text)
, JButton(Icon icon)
, JButton(String text, Icon icon)
, параметры которых говорят сами за себя. Пятый конструктор мы рассмотрим в следующей главе.
Кроме обычного значка можно назначить кнопке еще несколько — для различных состояний. Метод setRolloverIcon(Icon icon)
позволяет задать значок, который будет появляться при наведении на кнопку мыши, setPressedIcon(Icon icon)
— значок для кнопки в нажатом состоянии, setDisableIcon(Icon icon)
— значок для неактивной кнопки. Каждому из этих методов соответствует метод get.
Метод setMargin(Insets margin)
позволяет задать величину отступов от текста надписи на кнопке до ее полей. Объект класса Insets
, который передается в этот метод, может быть создан конструктором с четырьмя целочисленными параметрами, задающими величину отступов: Insets(int top, int left, int bottom, int right)
. Метод getMargin()
возвращает величину текущих отступов в виде объекта того же класса.
Все методы класса JLabel
, описанные в предыдущем разделе, присутствуют и в классе JButton
. С помощью этих методов можно изменять значок и текст надписи на кнопке, а также управлять их взаимным расположением друг относительно друга и относительно края кнопки (с учетом отступов).
Посредством методов setBorderPainted(boolean borderPainted)
, setFocusPainted(boolean focusPainted)
, setContentAreaFilled(boolean contentAreaFilled)
можно отключать (параметром false) и включать обратно (параметром true) прорисовку рамки, прорисовку фокуса (кнопка, на которой находится фокус, выделяется пунктирным прямоугольником) и закраску кнопки в нажатом состоянии.
Для примера создадим кнопку со значком и с надписью, изменим ее отступы и расположение текста относительно значка (текст будет выровнен влево и вверх относительно значка).
SimpleWindow(){
super("Окно с кнопкой");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JButton button = new JButton("Кнопка", new ImageIcon("1.gif"));
button.setMargin(new Insets(0, 10, 20, 30));
button.setVerticalTextPosition(SwingConstants.TOP);
button.setHorizontalTextPosition(SwingConstants.LEFT);
getContentPane().add(button);
pack();
}
Компоненты JToggleButton, JCheckBox, JRadioButton
Компонент JToggleButton
представляет собой кнопку, которая может находиться в двух состояниях: нажатом и отпущенном. Когда пользователь щелкает мышкой по такой кнопке, она изменяет свое состояние. Именно таким образом ведут себя кнопки форматирования на инструментальной панели текстового редактора. Кнопка [I] не только устанавливает или убирает курсивное начертание в выделенном тексте, но и сигнализирует о его наличии или отсутствии.
Основной конструктор — JToggleButton(String text, Icon icon, boolean selected)
создает кнопку с заданными надписью, значком и текущим состоянием. Кнопку можно перевести в требуемое состояние программным путем, вызвав метод setSelected(boolean selected)
. Метод isSelected()
возвращает true, если кнопка выбрана (т.е. находится в нажатом состоянии) и false в противном случает.
От класса JToggleButton
унаследован класс JCheckBox
— флажок. Этот класс имеет точно такой же набор конструкторов и методов, т.е. не расширяет функциональность предка. Единственное различие между ними — во внешнем виде: JCheckBox выглядит не как кнопка, а как небольшой квадратик, в котором можно поставить или убрать галочку.
Аналогичным образом ведет себя класс JRadioButton
— переключатель или радиокнопка, внешне выглядящая как пустой кружок, когда она не выделена и кружок с точкой в выделенном состоянии.
Несмотря на то, что классы JCheckBox
и JRadioButton
ведут себя абсолютно одинаково (и аналогично их общему предку JToggleButton
), их принято использовать в различных ситуациях. В частности, JRadioButton
предполагает выбор единственной альтернативы из нескольких возможных: несколько таких объектов объединяются в одну группу (чаще всего эта группа визуально обозначается рамкой) и при выборе одного из элементов группы предыдущий выбранный элемент переходит в состояние «не выбран».
Для того, чтобы получить такое поведение, используется специальный контейнер ButtonGroup
— взаимоисключающая группа (создается конструктором без параметров). Если добавить в один такой контейнер несколько элементов JRadioButton
, то выбранным всегда будет только один из них.
В принципе, в ButtonGroup
могут быть добавлены не только переключатели, но и флажки, и кнопки выбора (и даже обычные кнопки). Но при разработке интерфейса следует следовать устоявшемуся подходу, согласно которому во взаимоисключающую группу следует объединять объекты JRadioButton
(и, в некоторых случаях JToggleButton
), но не JCheckBox
.
Метод add(AbstractButton button)
* добавляет элемент в группу. Метод getElements()
возвращает все ее элементы в виде коллекции Enumeration
. По коллекции можно пройтись итератором и найти выделенный элемент.
Рассмотри пример, в котором создаются две кнопки выбора, два флажка и два переключателя. Кнопки выбора и переключатели объединены в группы ButtonGroup
. Для того, чтобы обвести каждую пару элементов рамкой, необходимо расположить каждую пару элементов на отдельной панели.
SimpleWindow(){
super("Пример с кнопками выбора, флажками и переключателями");
setDefaultCloseOperation(EXIT_ON_CLOSE);
ImageIcon icon = new ImageIcon("1.gif"); // будем использовать один значок на все случаи
Box mainBox = Box.createVerticalBox();
Box box1 = Box.createVerticalBox();
JToggleButton tButton1 = new JToggleButton("Кнопка выбора 1");
JToggleButton tButton2 = new JToggleButton("Кнопка выбора 2", icon);
ButtonGroup bg = new ButtonGroup(); // создаем группу взаимного исключения
bg.add(tButton1);
bg.add(tButton2); // сделали кнопки tButton1 и tButton2 взаимоисключающими
box1.add(tButton1);
box1.add(tButton2); // добавили кнопки tButton1 и tButton2 на панель box1
box1.setBorder(new TitledBorder("Кнопки выбора"));
Box box2 = Box.createVerticalBox();
JCheckBox check1 = new JCheckBox("Флажок 1");
JCheckBox check2 = new JCheckBox("Флажок 2", icon);
box2.add(check1);
box2.add(check2); // добавили флажки на панель box2
box2.setBorder(new TitledBorder("Флажки"));
Box box3 = Box.createVerticalBox();
JRadioButton rButton1 = new JRadioButton("Переключатель 1");
JRadioButton rButton2 = new JRadioButton("Переключатель 2", icon);
bg = new ButtonGroup(); // создаем группу взаимного исключения
bg.add(rButton1);
bg.add(rButton2); // сделали радиокнопки взаимоисключающими
box3.add(rButton1);
box3.add(rButton2); // добавили радиокнопки на панель box3
box3.setBorder(new TitledBorder("Переключатели"));
mainBox.add(box1);
mainBox.add(box2);
mainBox.add(box3);
setContentPane(mainBox);
pack();
}
Запустив пример, мы можем пронаблюдать особенности работы кнопок выбора, флажков и переключателей. В частности, мы видим, что у флажков или переключателей рисунок заменяет элемент выделения. Но рисунок не показывает, выбран ли данный объект, что может сбить пользователя с толку. Необходимо установить отдельный рисунок для выделенного состояния, что достигается методом setSelectedIcon(Icon icon)
. Добавьте в нужные места команды:
check2.setSelectedIcon(new ImageIcon("2.gif"));
и
rButton2.setSelectedIcon(new ImageIcon("2.gif"));
Пронаблюдайте произведенный эффект. Не забудьте, что файл 2.gif, равно как и файл 1.gif должны находиться в доступном для программы месте: в директории вашего проекта.
Упражнение.
В рассмотренном примере рамки имеют различную ширину. Измените пример таким образом, чтобы все рамки были одинаковы по ширине. Подсказка: используйте другой менеджер расположения главной панели (вместо BoxLayout
).
Текстовое поле JTextField
Текстовое поле — простой и часто используемый компонент, предназначенный для ввода небольших по объему (записываемых в одну строку) текстовых данных. Для создания текстового поля чаще всего используются конструкторы:
JTextField(int columns)
— создает пустое текстовое поле, ширина которого достаточна для размещения columns
символов. При этом пользователь может вводить в текстовое поле строку какой угодно длины: она просто будет прокручиваться.
JTextField(String text)
— создает текстовое поле с начальным текстом text
.
JTextField(String text, int columns)
— устанавливает и ширину и начальный текст.
Занести текст в поле можно методом setText(String text)
. Метод getText()
возвращает содержимое текстового поля целиком, а getText(int offset, int length)
— фрагмент содержимого длины length
, начиная с символа offset
.
Часть текста в поле может выделяться (как программным путем, так и в результате действий пользователя). Метод getSelectedText()
позволяет получить выделенную часть текста. Заменить выделенный текст другим можно с помощью метода replaceSelection(String content)
. Методы getSelectionStart()
и getSelectionEnd()
возвращают границы выделенного участка, а методы setSelectionStart(int start)
и setSelectionEnd(int end)
изменяют их.
Метод getCaretPosition()
возвращает позицию курсора (каретки) в текстовом поле, а метод setCaretPosition(int position)
позволяет задать ее программно. Методом setCaretColor(Color color)
можно изменить цвет курсора.
По умолчанию текст в поле прижимается к левому краю. Изменить это можно методом setHorizontalAlignment(int align)
, в качестве параметра передается одна из констант выравнивания, определенных в этом же классе JTextField:
LEFT
, CENTER
, RIGHT
.
Поле для ввода пароля JPasswordField
JPasswordField
является прямым потомком JTextField
, поэтому для него справедливо все сказанное выше. Отличие заключается в том, что весь введенный в него текст скрыт от посторонних глаз: он заменяется звездочками или другим символом, установить который позволяет метод setEchoChar(char echo)
, а получить — getEchoChar()
.
Чаще всего JPasswordField
применяется для ввода пароля. Метод getText()
позволяет получить этот пароль, но пользоваться им не рекомендуется (злоумышленник может проанализировать содержимое оперативной памяти и перехватить этот пароль). Вместо него следует использовать метод getPassword()
, возвращающий массив символов char[]
. После того, как введенный пароль будет обработан (например, сравнен с реальным паролем) рекомендуется заполнить этот массив нулями, чтобы следов в оперативной памяти не осталось.
Область для ввода текста JTextArea
JTextArea также является потомком JTextField
и наследует все его методы. В отличие от текстового поля область для ввода текста позволяет ввести не одну строку, а несколько. В связи с этим JTextArea
предлагает несколько дополнительных функций. Во-первых, это способность переносить слова на соседнюю строку целиком, которой управляет метод setWrapStyleWord(boolean wrapStyle)
. Если вызвать этот метод с параметром true, то слова не будут разрываться в том месте, где они «натыкаются» на границу компонента, а будут целиком перенесены на новую строку. Во-вторых, это способность переносить текст (то есть длинные строки будут укладываться в несколько строк вместо одной, уходящей за границы компонента. Этой способностью управляет метод setLineWrap(boolean lineWrap)
. Методы isWrapStyleWord()
и isLineWrap()
возвращают текущее состояние данных способностей (true — активирована и false — деактивирована).
При создании JTextArea
чаще всего используют конструктор JTextArea(int rows, int columns)
, устанавливающий высоту (количество строк) и ширину (количество символов) компонента.
Для работы со своим содержимым JTextArea
дополнительно предлагает два удобных метода. Метод append(String text)
добавляет строку text
в конец уже имеющегося текста, а метод insert(String text, int position)
вставляет ее в позицию position
.
Пронаблюдаем эти три компонента на наглядном примере. Создадим простое окно, в котором разместим их с помощью менеджера BorderLayout
.
SimpleWindow(){
super("Пример текстовых компонентов");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JTextField textField = new JTextField("Текстовое поле", 20);
textField.setCaretColor(Color.RED);
textField.setHorizontalAlignment(JTextField.RIGHT);
JPasswordField passwordField = new JPasswordField(20);
passwordField.setEchoChar('$');
passwordField.setText("пароль");
JTextArea textArea = new JTextArea(5, 20);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
for (int i = 0; i <= 20; i++)
textArea.append("Область для ввода текстового содержимого ");
getContentPane().add(textField, BorderLayout.NORTH);
getContentPane().add(textArea);
getContentPane().add(passwordField, BorderLayout.SOUTH);
pack();
}
Для того, чтобы лучше понять особенности работы текстовой области, замените по очереди true на false в вызовах методов setLineWrap()
и setWrapStyleWord()
. Пронаблюдайте за изменением работы компонента. Изменяйте размеры окна, чтобы видеть, каким образом текст перестраивается под доступное ему пространство.
Упражнение.
Расположите в окне те же самые три компонента, но с помощью менеджера размещения FlowLayout
, который всегда устанавливает для компонентов их предпочтительные размеры. Пронаблюдайте за тем, как ведет себя область JTextArea
при добавлении в нее нового текста.
Панель прокрутки JScrollPane
Наблюдая за поведением компонента JTextArea
в предыдущем примере, легко можно обнаружить проблемы, которые возникают, когда тексту становится «тесно» в рамках отведенного места. В зависимости от используемого менеджера расположения текст либо обрезается, уходя за границы компонента, либо раздвигает эти границы (но в любом случае остается ограничен размером окна). В таких случаях типично использование полос прокрутки, но в Swing полосы прокрутки сами собой не появляются.
К счастью, добавить к компоненту полосы прокрутки на самом деле очень просто. Для этого служит компонент JScrollPane
— панель прокрутки. Чаще всего она просто «надевается» на требуемый объект посредством собственного конструктора, принимающего этот объект в качестве параметра. Например, чтобы текстовая область textArea
из предыдущего примера обрела полосы прокрутки, необходимо заменить команду
getContentPane().add(textArea);
на команду
getContentPane().add(new JScrollPane(textArea));
В этой команде создается панель с полосами прокрутки, в нее помещается объект textArea
, а сама панель добавляется в панель содержимого окна. Теперь текст свободно прокручивается. А в случае применения менеджера FlowLayout
или BoxLayout
компонент JTextArea
не будет подстраиваться под свое содержимое (будет иметь предпочтительный размер, соответствующий параметрам конструктора) и, при необходимости, отображать полоски прокрутки.
Полезными методами JScrollPane являются:
setHorizontalScrollBarPolicy(int policy)
— позволяет задать стратегию работы с горизонтальной полосой прокрутки. Возможные значения представлены константами HORIZONTAL_SCROLLBAR_ALWAYS
(отображать всегда), HORIZONTAL_SCROLLBAR_AS_NEEDED
(отображать при необходимости) и HORIZONTAL_SCROLLBAR_NEVER
(не отображать никогда). Данные константы определены в интерфейсе ScrollPaneConstants
.
В интерфейсе ScrollPaneConstants
, не описано ни одного метода, а содержатся исключительно константы. Кстати, точно такой же «сборник констант» представляет собой класс SwingConstants
, использовавшийся для указания выравнивания в прошлой главе. Если класс (в наших примерах это SimpleWindow
) часто использует константы, определенные в подобном интерфейсе (например, для выравнивания множества компонентов), используется прием, позволяющий сократить объем кода. Класс может реализовать нужный интерфейс и использовать все его константы как свои. Например, мы могли бы переписать определение класса SimpleWindow
следующим образом:
class SimpleWindow extends JFrame implements ScrollPaneConstants {
...
}
и вместо ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
писать просто HORIZONTAL_SCROLLBAR_NEVER
везде, где это необходимо.
setVerticalScrollBarPolicy(int policy)
позволяет задать стратегию работы с вертикальной полосой прокрутки посредством констант VERTICAL_SCROLLBAR_ALWAYS
, VERTICAL_SCROLLBAR_AS_NEEDED
и VERTICAL_SCROLLBAR_NEVER
.*
Инструментальная панель JToolBar
Большинство программных продуктов предоставляют удобные инструментальные панели, расположенные вдоль границ окна программы и содержащие кнопки, выпадающие списки и другие элементы управления, обычно соответствующие командам меню. В Swing для инструментальных панелей разработан визуальный компонент JToolBar
, в котором заложена просто потрясающая функциональность.
На этот раз начнем сразу с примера. Создадим окно с менеджером расположения BorderLayout
, разместим по центру область для ввода текста JTextArea
, а к верхней границе прикрепим инструментальную панель с тремя кнопками и одним разделителем:
SimpleWindow(){
super("Пример использования JToolBar");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JTextArea textArea = new JTextArea(5, 20);
getContentPane().add(textArea);
JToolBar toolBar = new JToolBar("Инструментальная панель");
toolBar.add(new JButton("Кнопка 1"));
toolBar.add(new JButton("Кнопка 2"));
toolBar.addSeparator();
toolBar.add(new JButton("Кнопка 3"));
getContentPane().add(toolBar, BorderLayout.NORTH);
pack();
}
Запустите пример и поэкспериментируйте с инструментальной панелью. Попробуйте отсоединить ее от верхней границы окна и прикрепить к какой-либо другой. Отсоедините ее от границ окна так, чтобы панель стала самостоятельным окном. При этом панель всегда отображается над родительским окном, даже если именно оно, а не панель является активным. Если закрыть самостоятельную панель кнопкой с крестиком, она вернется в свое окно, в то место, где она была закреплена последний раз.
Итак, весьма простой пример продемонстрировал весьма впечатляющие возможности инструментальной панели. Подведем итог, перечислив самые полезные методы JToolBar
:
Конструктор JToolBar(String title)
создает горизонтальную панель с заданным заголовком. Горизонтальная панель предназначена для прикрепления к верхней либо нижней границе родительской панели (имеющей расположение BorderLayout
). Для создания вертикальной панели используется конструктор JToolBar(String title, int orientation)
, где параметр orientation
задается константой VERTICAL
из интерфейса SwingConstants
. Также доступны конструкторы JToolBar()
и JToolBar(int orientation)
, создающие панель без заголовка.
setFloatable(boolean floatable)
— разрешает либо запрещает (по умолчанию разрешает) пользователю откреплять панель от места ее начального расположения. Ему соответствует метод isFloatable()
возвращающий true, если откреплять панель разрешено.
add(Component component)
— добавляет на инструментальную панель новый элемент управления. Взаимосвязанные группы элементов управления принято разделять с помощью линии или пустого пространства. Метод addSeparator()
добавляет такой разделитель.
Выпадающий список JComboBox
Выпадающий список — весьма распространенный элемент управления. Он содержит множество вариантов, из которых пользователь может выбрать один и только один, либо (если выпадающий список это позволяет) ввести свой собственный.
Создать выпадающий список можно конструктором по умолчанию JComboBox()
, после чего добавлять в него элементы методом addItem(Object item)
, добавляющим новый элемент в конец списка, или методом insertItemAt(Object item, int index)
, позволяющим уточнить позицию, в которую требуется вставить элемент. Однако проще использовать конструктор, в котором сразу указываются все элементы выпадающего списка. Таких конструкторов два: JComboBox(Object[] elements)
и JComboBox(Vector elements)
. Работают они одинаково, так что это вопрос удобства разработчика: использовать массив или вектор.
Чаще всего в выпадающий список добавляют строки, однако, как это следует из сигнатур описанных выше методов, он может содержать вообще любые объекты. Любой объект преобразуется к строке методом toString()
, именно эта строка и будет представлять его в выпадающем списке.
Метод getItemAt(int index)
позволяет обратиться к произвольному элементу.
Метод removeAllItems()
удаляет из JComboBox
все элементы, а метод removeItem(Object item)
— конкретный элемент (при условии, что он содержался в списке).
Метод getSelectedIndex()
позволяет получить индекс выбранного пользователем элемента (элементы нумеруются начиная с нуля), а метод getSelectedItem()
возвращает сам выбранный объект. Сделать конкретный элемент выбранным можно и программно, воспользовавшись методом setSelectedIndex(int index)
или setSelectedItem(Object item)
.
Чтобы пользователь мог ввести свой вариант, который не присутствует в списке, должен быть вызван метод setEditable(boolean editable)
с параметром true. Ему соответствует метод isEditable()
.
Рассмотрим пример, в котором создается выпадающий список из 3 элементов и выбирается 2-й. Строка, представляющая третий элемент, использует HTML-теги. Как показывает результат, они работают не только в метках*.
SimpleWindow(){
super("Пример использования JComboBox");
setDefaultCloseOperation(EXIT_ON_CLOSE);
String[] elements = new String[] {"Вася", "Петя",
"<html><font size = +1 color = yellow>Иван</font>"};
JComboBox combo = new JComboBox(elements);
combo.setSelectedIndex(1);
JPanel panel = new JPanel();
panel.add(combo);
setContentPane(panel);
setSize(200,200);
}
Ползунок JSlider
Ползунок позволяет пользователю выбрать некоторое число из диапазона доступных значений, наглядно представив этот диапазон. Против наглядности у ползунка есть один недостаток: он занимает достаточно много места.
Основной конструктор ползунка: JSlider(int orientation, int min, int max, int value)
. Первый параметр — ориентация ползунка (HORIZONTAL
или VERTICAL
). Остальные параметры указывают соответственно минимальное, максимальное и текущее значение. Изменить эти значения позволяют методы setOrientation(int)
, setMinimum(int min)
, setMaximum(int max)
, setValue(int value)
, а получить текущие — соответствующие им методы get. Чаще всего, конечно, используется метод getValue()
— чтобы определить, какое значение выбрал при помощи ползунка пользователь.
Шкала ползунка может быть украшена делениями. Метод setMajorTickSpacing(int spacing)
позволяет задать расстояние, через которое будут выводиться большие деления, а метод setMinorTickSpacing(int spacing)
— расстояние, через которые будут выводиться маленькие деления. Метод setPaintTicks(boolean paint)
включает или отключает прорисовку этих делений. Метод setSnapToTicks(boolean snap)
включает или отключает «прилипание» ползунка к делениям: если вызвать этот метод с параметром true, пользователь сможет выбрать при помощи ползунка только значения, соответствующие делениям. Наконец, метод setPaintLabels(boolean paint)
включает или отключает прорисовку меток под большими делениями.
Пример использования перечисленных методов:
SimpleWindow(){
super("Пример использования JSlider");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JSlider slider = new JSlider(JSlider.HORIZONTAL, 50, 150, 70);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(5);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setSnapToTicks(true);
JPanel panel = new JPanel();
panel.add(slider);
setContentPane(panel);
pack();
}
Панель со вкладками JTabbedPane
Многим программам бывает необходимо разместить в одном окне большое количество элементов управления, некоторые из которых (такие как списки, деревья, текстовые области и т.д.) могут к тому же занимать приличное пространство. Чаще всего такая необходимость возникает, когда для работы программе необходимо множество входных данных. Для того, чтобы не вводить дополнительных окон и не перегружать интерфейс, часто используется панель с закладками. Ее можно воспринимать как множество страниц (вкладок), каждая из которых занимает все доступное пространство, за исключением полосы с краю (это может быть любой край), где отображаются ярлычки с названиями страниц. Когда пользователь щелкает по ярлычку, открывается соответствующая ему страница. На каждой странице размещено несколько элементов управления (как правило, они группируются по смыслу).
Создать панель со вкладками можно простым конструктором, в котором определяется только месторасположение ярлычков (LEFT
, RIGHT
, TOP
или BOTTOM
). Но иногда бывает полезен конструктор JTabbedPane(int orientation, int layout)
, где второй параметр принимает значения, соответствующие константам SCROLL_TAB_LAYOUT
(если все ярлычки не помещаются, появляется полоса прокрутки) или WRAP_TAB_LAYOUT
(ярлычки могут располагаться в несколько рядов).
После этого можно добавлять вкладки методом addTab()
, имеющим несколько вариантов. В частности, метод addTab(String title, Component tab)
добавляет закладку с указанием текста ярлычка, а метод addTab(String title, Icon icon, Component tab)
позволяет задать также и значок к ярлычку. В качестве вкладки обычно служит панель с размещенными на ней элементами управления.
Создадим панель с десятью вкладками, на каждой из которых поместим по кнопке. Все эти вкладки создадим в цикле for, чтобы не писать много кода.
SimpleWindow(){
super("Пример использования JTabbedPane");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);
for (int i = 1; i <= 10; i++) {
JPanel panel = new JPanel();
panel.add(new JButton("Кнопка № " + i));
tabbedPane.add("Панель " + i, panel);
}
getContentPane().add(tabbedPane);
setSize(300,200);
}
Упражнение.
Измените пример, чтобы вкладки располагались не в несколько рядов, а прокручивались и, кроме того, добавьте к ярлыку четвертой вкладки значок. Результат должен выглядеть так, как изображено на рисунке.
Список JList
Список JList
— это один из сложных компонентов, для эффективной работы с которыми необходимо понимание основ библиотеки Swing, в частности, концепции «Модель-Вид». Компоненты JTree
(дерево) и JTable
(таблица) еще сложнее и в данном пособии не рассматриваются. Что касается списка, то некоторая часть его возможностей может быть использована без углубления в детали.
Список содержит группу элементов, аналогично выпадающему списку JComboBox
, но обладает двумя отличительными особенностями. Во-первых, на экране видны одновременно несколько элементов списка. Во-вторых, пользователь может выбрать в списке не один элемент, а несколько (если установлен соответствующий режим выделения).
Создать список можно с помощью конструктора, работающего на основе массива Object[]
или вектора Vector
(аналогично JComboBox
). Метод setVisibleRowCount(int count)
устанавливает количество видимых элементов списка. Остальные элементы будут уходить за его пределы или прокручиваться, если поместить список в JScrollPane
(что рекомендуется).
По умолчанию пользователь может выбрать в списке любое число элементов, держа нажатой клавишу Ctrl
. Это можно изменить, вызвав метод setSelectionMode(int mode)
, где параметр задается одной из констант класса ListSelectionModel
:
SINGLE_SELECTION
— может быть выделен только один элемент,
SINGLE_INTERVAL_SELECTION
— может быть выделено несколько элементов, но составляющих непрерывный интервал,
MULTIPLE_INTERVAL_SELECTION
— может быть выделено произвольное количество смежных и несмежных элементов.
Выделенный элемент списка (если он один) можно получить методом getSelectedValue()
. Если таких несколько, метод вернет первый из них. Метод getSelectedValues()
возвращает все выделенные элементы списка в виде массива Object[]
. Аналогично работают методы getSelectedIndex()
и getSelectedIndices()
, только возвращают они не сами выделенные элементы, а их индексы. Всем этим методам соответствуют методы set, так что выделить элементы списка можно и программно.
Следующий пример иллюстрирует некоторые из этих возможностей JList
:
SimpleWindow(){
super("Пример с JList");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Object[] elements = new Object[] {"Колбаса", "<html><font color = red>Масло", "Сгущенное молоко"};
JList list = new JList(elements);
list.setVisibleRowCount(5);
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
list.setSelectedIndices(new int[] {1,2});
getContentPane().setLayout(new FlowLayout());
getContentPane().add(new JScrollPane(list));
setSize(200,150);
}
Для того, чтобы эффективно добавлять и удалять элементы из списка, управлять их отображением, добавлять и удалять выделенные элементы поодиночке, необходимо познакомиться с моделью данных списка, что выходит за рамки настоящего пособия.
Окно входа в систему
В качестве реального примера законченного окна, иллюстрирующего положения этой и предыдущей глав, рассмотрим окно для входа в систему (которое является необходимой частью каждого из итоговых заданий). Это окно содержит два текстовых поля для ввода логина и пароля, подписи к этим полям и кнопки «OK» и «Отмена».
В первую очередь необходимо сделать на бумаге (или с помощью специализированного программного средства рисования интерфейсов, такого как Microsoft Visio) эскиз будущего окна, чтобы определиться, где должны быть расположены элементы управления и какой менеджер расположения должен быть выбран.
В нашем окне нет элементов, которые имеет смысл растягивать на все доступное пространство, поэтому будем использовать один из менеджеров, сохраняющих предпочтительные размеры компонентов, а именно — BoxLayout
. Проще всего представить наше окно как три горизонтальные панели, объединенные в одной вертикальной. В первой из них будет надпись «Логин:» и текстовое поле. Во второй — надпись «Пароль:» и поле для ввода пароля. В третьей будут размещены две кнопки. При этом необходимо учесть следующее:
- Кнопки «ОК» и «Отмена» принято прижимать к правому краю окна, поэтому в начале третьей горизонтальной панели необходимо добавить «пружину».
- Должно выдерживаться аккуратное расстояние между элементами. В частности, для стиля Java разработаны следующие рекомендации. Тесно связанные элементы (такие как текстовое поле и подпись к нему) должны отстоять друг от друга на 6 пикселов. Логически сгруппированные элементы — на 12 пикселов (в нашем случае это две верхние панели и пара кнопок). Все остальные элементы должны находиться на расстоянии 17 пикселов друг от друга. Не следует забывать и про рамку окна.
- Элементы должны быть аккуратно выровнены. В нашем случае надписи, которые мы собираемся поместить перед текстовыми полями, наверняка будут разной длины и из-за этого поля будут сдвинуты относительно друг друга, что не желательно. Поэтому следует принудительно задать у надписей одинаковую ширину.
- При увеличении размеров окна текстовые поля будут неэстетично изменять свою высоту. Можно ее зафиксировать, а можно просто запретить окну изменять свои размеры после упаковки командой
setResizable(false)
.
Итоговый код окна приведен ниже. Рекомендуется не только набрать и протестировать, но и внимательно разобрать его.
public class LoginWindow extends JFrame {
/* Для того, чтобы впоследствии обращаться к содержимому текстовых полей, рекомендуется сделать их членами класса окна */
JTextField loginField;
JPasswordField passwordField;
LoginWindow(){
super("Вход в систему");
setDefaultCloseOperation(EXIT_ON_CLOSE);
// Настраиваем первую горизонтальную панель (для ввода логина)
Box box1 = Box.createHorizontalBox();
JLabel loginLabel = new JLabel("Логин:");
loginField = new JTextField(15);
box1.add(loginLabel);
box1.add(Box.createHorizontalStrut(6));
box1.add(loginField);
// Настраиваем вторую горизонтальную панель (для ввода пароля)
Box box2 = Box.createHorizontalBox();
JLabel passwordLabel = new JLabel("Пароль:");
passwordField = new JPasswordField(15);
box2.add(passwordLabel);
box2.add(Box.createHorizontalStrut(6));
box2.add(passwordField);
// Настраиваем третью горизонтальную панель (с кнопками)
Box box3 = Box.createHorizontalBox();
JButton ok = new JButton("OK");
JButton cancel = new JButton("Отмена");
box3.add(Box.createHorizontalGlue());
box3.add(ok);
box3.add(Box.createHorizontalStrut(12));
box3.add(cancel);
// Уточняем размеры компонентов
loginLabel.setPreferredSize(passwordLabel.getPreferredSize());
// Размещаем три горизонтальные панели на одной вертикальной
Box mainBox = Box.createVerticalBox();
mainBox.setBorder(new EmptyBorder(12,12,12,12));
mainBox.add(box1);
mainBox.add(Box.createVerticalStrut(12));
mainBox.add(box2);
mainBox.add(Box.createVerticalStrut(17));
mainBox.add(box3);
setContentPane(mainBox);
pack();
setResizable(false);
}
}
Заключение
Мы сделали лишь краткий обзор компонентов Swing. Нами не были упомянуты некоторые полезные компоненты, такие как индикатор состояния процесса JProgressBar, счетчик JSpinner, панель с разделительной полосой JSplitPane, а также ряд мощных текстовых компонентов. Многие из рассмотренных в этой главе компонентов внушительными возможностями, оставшимися за рамками нашего обзора. И хотя на основе материала этой и следующей, а также предыдущей глав можно разработать полноценный графический интерфейс, необходимый для выполнения основного задания, для профессиональной работы с библиотекой Swing необходимо обратиться к полноценным учебникам и справочникам.
Дополнительная литература
1. Хабибуллин И.Ш. Самоучитель Java 2. (главы 11 - 14)
2. И.Портянкин. Swing. Эффективные пользовательские интерфейсы.
Особое внимание обратите на так называемы модели, которые не рассматривались в настоящем пособии. Понятие модели является ключевым для таких элементов управления как список JList, дерево JTree и таблица JTable. Многие из рассмотренных выше компонентов тоже имеют свои модели, посредством которых можно серьезно повысить эффективность их работы.