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

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

370

ГЛАВА 12

}

if ( value.equals(data[1]) ) { setText("<html><h3><font color=\"green\">"

+ value);

}

if ( value.equals(data[2]) ) { setText("<html><h4><font color=\"blue\">"

+ value);

}

}

// размер редактора

public Dimension getPreferredSize() { return new Dimension(100, 30);

}

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new SpinnerLabelEditor(); } });

}

}

Здесь в окно добавляется один простой счетчик на основе модели SpinnerListModel, данные которой хранятся в массиве. Самое интересное — это внутренний класс LabelEditor, унаследованный от надписи JLabel и реализующий интерфейс слушателя событий ChangeListener (интерфейс этого слушателя обязательно нужно реализовывать любому редактору, иначе он не сможет узнавать об изменении текущего элемента счетчика). Вся работа происходит в методе слушателя stateChanged(), он вызывается при смене текущего значения счетчика. Мы находим источник события, подразумевая, что это счетчик JSpinner (хотя можно присоединить слушателя и к модели SpinnerModel), получаем текущее значение счетчика и обрабатываем его. Нам известно, что значения у нас всего три, так что каждое из них редактор обрабатывает по своему, «выкрашивая» в подходящий цвет. Обратите внимание на метод getPreferredSize(): он возвращает намеренно больший размер, в противном случае размер надписи менялся бы динамически в зависимости от отображаемого элемента, а это привело бы не к самому лучшему результату на экране.

После создания редактора остается присоединить его к счетчику. Для этого нужно не только передать его счетчику методом setEditor(), но и зарегистрировать как слушателя событий ChangeListener. В примере это сделано не слишком элегантно, лучше было бы передать ссылку на счетчик в конструктор редактора, и уже в этом конструкторе провести регистрацию слушателя. Также имеется и еще одна маленькая хитрость — наша надпись отображает что-либо только после получения события ChangeListener, а пока пользователь не начнет прокручивать счетчик, это событие не произойдет. Нам приходится вручную поменять значение модели, что приведет к запуску события ChangeListener, и обновлению нашей надписи (в противном случае после запуска счетчик отображал бы пустое поле). Пожалуй, проще было бы присоединить модель после того, как присоединен редактор. Запустив программу с примером, вы увидите, как отображаются разные элементы счетчика, и это только начало — нам прекрасно известно, на что способна надпись JLabel.

Диапазоны значений

371

В качестве красочного редактора можно использовать и компонент JEditorPane, примерно так, как мы это делали в главе 11 для раскрывающихся списков JComboBox, и тем самым еще больше повысить гибкость и элегантность своего приложения.

Резюме

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

Глава 13. Управление пространством

Вглаве 7 мы уже знакомились с вариантами размещения компонентов в контейнере

изнаем, что для этого используются разнообразные менеджеры расположения. С их помощью вы сможете создать любой необходимый вам пользовательский интерфейс и расположить компоненты в контейнере так, как планировалось. Однако не все ситуации можно разрешить только средствами контейнеров и подходящих менеджеров расположения — в вашем приложении, особенно если оно сложное или обладает множеством вариантов настройки, может быть огромное количество разнообразных компонентов, которые просто физически не смогут уместиться на экране. Кроме того, существуют ситуации, когда размер какого-либо компонента намного превышает доступное пространство экрана. В решении проблемы иногда может помочь применение дополнительных диалоговых окон, но их излишнее количество запутывает пользователя, особенно если одни диалоговые окна приходится вызывать из других.

С недостатком места в контейнере призваны справляться специальные компоненты, которые мы и будем рассматривать в этой главе. К таким компонентам, прежде всего, относится панель с вкладками JTabbedPane, которая в удобной и наглядной форме

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

Далее мы рассмотрим разделяемую панель JSplitPane, в обязанности которой входит гибкое распределение пространства между двумя компонентами. С ее помощью пользователь может сделать больше тот компонент, который его в данный момент интересует, произвольным образом меняя соотношение доступных размеров компонентов.

Наконец, остается панель прокрутки JScrollPane, отображающая только часть некоторого компонента и с помощью специальных полос прокрутки (JScrollBar) легко позволяющая перемещаться к любой другой его части. Первые два компонента довольно просты, и их функции очевидны, так что их изучение не займет у нас много времени, а вот панель прокрутки настолько часто гостит в пользовательских интерфейсах, что ее стоит рассмотреть подробнее, к тому же, как вы узнаете, она способна на многое.

Панель с вкладками JTabbedPane

Как нетрудно догадаться по названию, панель с вкладками JTabbedPane позволяет выводить на экран так называемыми вкладки (tabs) — панели с небольшими ярлычками с краю (это может быть любой из краев панелей — верхний, нижний, левый или правый). При щелчке пользователем на ярлычке панель JTabbedPane выводит на экран соответствующие выбранной вкладке элементы пользовательского интерфейса. Таким образом у вас появляется возможность сэкономить место в контейнере: вместо размещения всех компонентов пользовательского интерфейса в одной панели содержимого вы разбиваете их (чаще всего по смыслу и предназначению) на несколько групп, добавляете каждую группу в отдельную панель, и передаете эти панели в компонент JTabbedPane, заодно

Управление пространством

373

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

Использовать панель с вкладками JTabbedPane очень просто. В основном работа с ней заключается в вызове метода add() или addTab() (лучше остановить свой выбор на втором методе, его название лучше соответствует производимому действию и параметры этого метода удобнее настраивать), которому необходимо передать компонент, соответствующий вкладке, надпись для ярлычка вкладки и значок, если вы его используете. После добавления всех вкладок панель JTabbedPane выводится на экран, при этом стоит проследить за тем, чтобы занимаемого ею места было достаточно не только для тех вкладок, которые вы добавили в нее, но и для соответствующих этим вкладкам компонентов. Рассмотрим небольшой пример использования панели JTabbedPane и убедимся, что она на самом деле проста:

//SimpleTabbedPanes.java

//Использование панелей с вкладками import javax.swing.*;

import java.awt.*;

public class SimpleTabbedPanes extends JFrame { public SimpleTabbedPanes() {

super("SimpleTabbedPanes"); setDefaultCloseOperation(EXIT_ON_CLOSE);

//первая панель с вкладками

JTabbedPane tabsOne = new JTabbedPane( JTabbedPane.BOTTOM, JTabbedPane.SCROLL_TAB_LAYOUT);

//добавляем вкладки

for (int i=1; i<8; i++) { JPanel tab = new JPanel();

tab.add(new JButton("Просто кнопка " + i)); tabsOne.addTab("Вкладка №: " + i, tab);

}

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

JTabbedPane tabsTwo = new JTabbedPane(JTabbedPane.TOP);

//добавляем вкладки

for (int i=1; i<8; i++) { JPanel tab = new JPanel();

tab.add(new JButton("Снова кнопка " + i)); tabsTwo.addTab("<html><i>Вкладка №: " + i,

374

ГЛАВА 13

new ImageIcon("icon.gif"), tab, "Нажмите " + i + "!");

}

//добавляем вкладки в панель содержимого setLayout(new GridLayout()); add(tabsOne);

add(tabsTwo);

//выводим окно на экран

setSize(600, 250); setVisible(true);

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new SimpleTabbedPanes(); } });

}

}

В примере мы создаем окно (довольно большого размера — нам нужно, чтобы в нем поместились все наши вкладки) и размещаем в нем две панели с вкладками JTabbedPane. Первая панель создается с помощью конструктора, принимающего два параметра: первый отвечает за расположение ярлычков вкладок (мы выбрали расположение внизу панели, но вы можете выбрать любую из четырех сторон панели, каждой из сторон соответствует своя константа класса JTabbedPane), а второй позволяет указать, как вкладки будут располагаться на экране в том случае, если их не удастся разместить в один ряд. По умолчанию вкладки располагаются в несколько рядов (аналогично действует менеджер последовательного расположения FlowLayout, когда ему не хватает места для размещения всех компонентов в одну строку), такому поведению соответствует константа WRAP_ TAB_LAYOUT, но для первой панели мы выбрали второй вариант расположения вкладок (которому отвечает константа SCROLL_TAB_LAYOUT): в одну строку вместе с небольшими кнопками прокрутки. Такое расположение вкладок позволяет сэкономить место, хотя и не дает возможности видеть ярлычки сразу всех вкладок. Вкладки мы добавляем в цикле методом addTab(), в качестве содержимого каждой вкладки используется панель JPanel, в которую помещена кнопка. Чтобы вы могли отличать вкладки и их содержимое друг от друга, мы добавили в надписи на ярлычках вкладок и на кнопках их порядковые номера. Метод addTab() очень прост: ему нужно передать строку с названием вкладки и ее содержимое.

Вторая панель JTabbedPane создается с помощью более простого конструктора: в нем мы указываем лишь расположение ярлычков вкладок (наверху панели), а способ размещения вкладок на экране оставляем заданным по умолчанию (как мы уже упоминали, по умолчанию вкладки располагаются в несколько рядов). Вкладки мы добавляем в цикле, так же как и в первом случае, но на этот раз используем более функциональную перегруженную версию метода addTab(). Она принимает сразу четыре параметра: надпись для ярлычка вкладки, значок, компонент, который будет соответствовать вкладке, и текст всплывающей подсказки (панель JTabbedPane позаботится о том, чтобы у каждой вкладки была собственная подсказка, если вы ее задаете). Кроме того что вы можете задать текст вместе со значком, для текста доступен прекрасно вам «знакомый» формат HTML: надо лишь указать в начале строки «волшебные» символы <html> (впрочем, текст может быть и пустой ссылкой null, в таком случае у вкладки будет только значок). Учитывая,

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