You are on page 1of 21

5.

Компоненти інтерфейсу користувача в Swing


5.1. Бібліотека Swing і проектний шаблон MVC.
Проектних шаблон MVC (molel-view-controller, модель - вид (вигляд,
представлення) - контролер) зробив величезний вплив на архітектуру Swing. Але
що таке «проектний шаблон».
Проектні шаблони
При вирішенні конкретних завдань більшість людей зазвичай керуються своїм або
чужим досвідом. Проектні шаблони - це спосіб представлення набутого досвіду
в структурованому вигляді. Піонерами в створенні таких шаблоном були
архітектори. Розробники програмного забезпечення також стали збирати каталоги
таких шаблонів.
Кожен шаблон слідує певному формату. Спочатку описується контекст, тобто
ситуація, яка породжує задачу проектування. Потім ставиться завдання, зазвичай
у вигляді конфліктуючих між собою обмежень. І на закінчення пропонується її
рішення, в якому досягається компроміс між суперечливими вимогами.
У проектному шаблоні MVC контекстом є система інтерфейсу користувача, яка
представляє інформацію і отримує дані від користувача. У ній існує кілька
суперечностей. До них можуть відноситись різні візуальні подання одних і тих же
даних, які повинні одночасно оновлюватися. Візуальне уявлення може
змінюватися в залежності від стилю користувальницького інтерфейсу. Механізми
взаємодії також можуть змінюватися, наприклад, для того, щоб підтримувати
виконання команд, які вводяться голосом. Вирішення цього завдання полягає в
розподілі відповідальності між трьома різними взаємодіючими складовими
шаблону: моделлю, видом і контролером.
Крім шаблону MVC в бібліотеках AWT і Swing. використовується ряд інших
шаблонів.
• Контейнери та компоненти служать прикладами шаблону "Компоновщик".
• прокручувати панель служить прикладом шаблону "Декоратор".
• Диспетчери компонування слідують шаблоном "Стратегія".
Проектний шаблон MVC
З чого складаються компоненти GUI, наприклад, екранна кнопка, прапорець,
текстове поле або складне вікно управління деревовидної структурою елементів.
Кожен з цих компонентів має наступні характеристики.
• Вміст, наприклад, стан кнопки (натиснута або відпущена) або текст в поле
редагування.
• Зовнішній вигляд (колір, розмір і т.д.).
• Поведінка (реакція на події).
Ці характеристики тісно пов'язані між собою. Наприклад, зовнішній вигляд екранної
кнопки залежить від візуального стилю інтерфейсу в цілому. Крім того, зовнішній
вигляд залежить від стану екранної кнопки: в натиснутому стані кнопка повинна
виглядати інакше, ніж в відпущеному. Стан, в свою чергу, залежить від подій. Якщо
користувач клацнув на екранній кнопці, вона вважається натиснутою.
Програмісти, які реалізують елементи GUI, повинні ретельно обмірковувати їх
внутрішній устрій і функціонування, щоб всі ці компоненти правильно працювали
незалежно від обраного візуального стилю.
Для вирішення подібних завдань розробники бібліотеки Swing звернулися до
проектного шаблону MVC. В основу цього шаблону покладені принципи ООП, один
з яких говорить: не перевантажувати об'єкт занадто великою кількістю завдань.
Клас, передбачений для кнопки, не зобов'язаний робити відразу все.
Тому стиль компонента зв'язується з одним об'єктом, а його вміст - з іншим.
Проектний шаблон MVC дозволяє досягти цієї мети, реалізувавши три окремих
класи.
• Клас моделі, в якому зберігається вміст.
• Клас виду (уявлення, view), який відображає вміст.
• Клас контролера, що обробляє введені користувачем дані.
Модель зберігає вміст і не реалізує інтерфейс користувача. Вміст екранної кнопки
тривіальний - це невеликий набір ознак, що означають, натиснута кнопка або
відпущена, активізована або неактивізована і т.д. Вмістом текстового поля є
символьний рядок, що не збігається з уявленням.
Модель повинна реалізовувати методи, які змінюють вміст і розкривають його
зміст. Наприклад, модель текстового поля має методи для введення символів в
рядку, їх видалення і повернення тексту у вигляді рядка. Модель невидима.
Відображення всіх відомостей, що зберігаються в моделі, - завдання
виду(уявлення).
Одна з переваг шаблону "модель-уявлення-контролер" полягає в тому, що модель
може мати кілька видів (view), кожне з яких відображає окремий аспект її вмісту.
Наприклад, редактор HTML-розмітки документів часто пропонує одночасно два
подання одних і тих же даних: WYSIWYG (Що бачиш на екрані, то і отримаєш при
друку) і ряд дескрипторів. Коли контролер оновлює модель, змінюються обидва
подання. Отримавши повідомлення про зміну, view оновлюється автоматично.
Контролер обробляє події, пов'язані з інформацією, що надходить від користувача,
наприклад, клацання кнопками миші і натиснення клавіш, а потім вирішує,
перетворювати ці події в зміни моделі або виду (view). Так, якщо користувач
натисне клавішу символу при введенні в текстовому полі, контролер викличе з
моделі команду "вставити символ". Потім модель повідомить view оновити
зображення. View взагалі невідомо, чому змінився текст. Але якщо користувач
натиснув клавішу управління курсором, то контролер може віддати View команду
на прокрутку. Прокрутка не змінює текст, тому моделі нічого невідомо про цю
подію.
У кожного компонента користувальницького інтерфейсу є клас-оболонка
(наприклад, JButton або JTextField), в якому зберігаються модель (model) і її вид
(view). Якщо вас цікавить вміст (наприклад, текст у відповідному полі), клас-
оболонка запросить модель і поверне відповідь. А якщо вас цікавить зміна
зовнішнього вигляду (наприклад, положення курсору в текстовому полі), то клас-
оболонка направить відповідний запит до view.
Відокремлюючи модель від призначеного для користувача інтерфейсу, розробники
Swing отримали можливість повторно використовувати код моделі і навіть міняти
візуальний стиль інтерфейсу в ході виконання програми.
Немає такого шаблону, який був би придатним на всі випадки життя. Розробники
Swing виявили, що на практиці не завжди вдається точно слідувати шаблоном
MVC. Моделі легко розділяються, і кожен компонент інтерфейсу має свій клас
моделі. Але завдання, які стоять перед view і контролером, не завжди чітко
відокремлюються одна від одної, тому при розподілі їх між різними класами
виникають труднощі.
Аналіз екранних кнопок в Swing за шаблоном MVC
Екранна кнопка - чи не найпростіший елемент призначеного для користувача
інтерфейсу, і тому її зручно вибрати в якості наочного посібника для вивчення
шаблону MVC. Аналогічний підхід застосовується і до більш складних компонентів
Swing.
Для більшості компонентів класи моделі реалізують інтерфейси, імена яких
закінчуються словом Model. Зокрема, для екранних кнопок використовується
інтерфейс ButtonModel. Класи, що реалізують цей інтерфейс, можуть визначати
стан різнотипних екранних кнопок. Кнопки настільки прості, що для них в бібліотеці
Swing передбачений окремий клас DefaultButtonModel, який реалізує даний
інтерфейс. Зрозуміти, якого роду дані підтримуються в моделі кнопки, можна,
розглянувши властивості інтерфейсу ButtonModel.

Відзначимо, що одна і та ж модель (а саме DefaultButtonModel) використовується


для підтримки звичайних кнопок, прапорців, кнопок-перемикачів і навіть для
пунктів меню. Зрозуміло, кожна з цих різновидів екранних кнопок має свій власний
вигляд (view) і окремий контролер. Якщо реалізується інтерфейс в стилі Metal, то в
якості view в класі JButton використовується клас BasicButtonUI, а як контролер -
клас ButtonUIListener. Загалом, у кожного компонента бібліотеки Swing є
пов'язаний з ним об'єкт view, назва якого закінчується на UI. Але не у всіх
компонентів Swing є свій власний об'єкт контролера.
Що ж насправді являє собою клас JButton? Це просто клас-оболонка, похідний від
класу JComponent і містить об'єкт типу DefaultButtonModel, деякі дані, необхідні
для відображення (наприклад, мітку кнопки і її піктограму), а також об'єкт типу
BasicButtonUI, який реалізує вид (view) екранної кнопки.
5.2. Введення в компоновку компонентів інтерфейсу
Розглянемо коротко яким чином компоненти розміщуються у фреймі. На відміну
від VisualBasic, в JDK відсутній візуальний конструктор форм, і тому доводиться
самостійно писати код для розміщення компонентів для користувача інтерфейсу у
фреймі.
У деяких IDE передбачені засоби, що автоматизують деякі із завдань
компонування GUI. Незважаючи на це необхідно уявляти, яким чином
розміщуються компоненти. Адже навіть ті GUI, які автоматично побудовані за
допомогою найдосконаліших інструментальних засобів, зазвичай потребують
ручного доопрацювання.
Знову подивимося приклад програми, де екранні
кнопки служили для зміни кольору фону в кадрі.
Екранні кнопки містяться в об'єкті типу JPanel і
управляються диспетчером потокової
компонування - стандартним диспетчером для
компонування панелі (FlowLayout).
Кнопки відцентровані. Якщо кнопки не
поміщаються в поточному ряду (малий розмір фрейму або велика кількість
кнопок), вони переносяться в новий ряд.
Компоненти розміщуються в контейнерах, а диспетчер компонування визначає
порядок розташування і розміри компонентів в контейнері.
У кожного контейнера є свій диспетчер компонування за
замовчуванням, але можна встановити власний
диспетчер компонування.
panel.setLayout(new GridLayout(4,4));
panel.setLayout(new FlowLayout());
Коли компоненти вводяться в контейнер, метод add()
контейнера приймає компонент і директиви по
розміщенню, необхідні для диспетчера компонування.
Гранична компоновка
Диспетчер граничною компонування (BorderLayout) за замовчуванням
вибирається для панелі вмісту в об'єкті типу JFrame. Цей диспетчер дозволяє
вибрати місце для кожного компонента. Компонент можна розмістити в центрі
панелі, в її верхній або нижній частині, а також зліва чи справа.
frame.add(component, BorderLayout.SOUTH);
При зміні розмірів контейнера розміри
компонентів, розташованих по краям,
залишаються колишніми, а змінюються лише
розміри центральної області. При введенні
компонента на панелі вказуються константи
CENTER (Центр), NORTH (Північ), SOUTH
(Південь), EAST (Схід) або WEST (Захід), задані
в класі BorderLayout. Займати всі місця на
панелі зовсім не обов'язково. Якщо не вказано
жодного значення, то за замовчуванням
приймається константа CENTER, тобто
розташування по центру.
При граничному компонуванні компоненти
розтягуються, щоб заповнити вільний простір. (При потоковому компонуванні
кращі (preffered) розміри кожного компонента залишаються без зміни.)
frame.add(yellowButton, BorderLayout.SOUTH);
Кнопка заповнить всю нижню частину фрейму.
Якщо ж спробувати вставити в нижній частині
фрейму ще одну кнопку, вона просто замінить
попередню. Як вихід можна скористатися
додатковими панелями.
JPanel panel = new JPanel();
panel.add(yellowButton);
panel.add(blueButton);
panel.add(redButton);
frame.add(panel, BorderLayout.SOUTH);
Зі звичайною панеллю за замовчуванням
зв'язується диспетчер потокового
компонування (FlowLayout). Розташування і
розміри кнопок визначаються диспетчером
FlowLayout (кнопки будуть вирівняні по центру
панелі, а їх розміри не будуть збільшені для
заповнення всього вільного простору). Панель з
трьома кнопками розташовується в нижній
частині панелі вмісту фрейма. Гранична компоновка розтягує панель з трьома
кнопками, щоб вона зайняла всю нижню (південну) область фрейма.
Сіткова компоновка
При сітковому компонуванні (GridLayout) компоненти розташовуються рядами і
стовпцями, як в таблиці. Але в цьому випадку розміри всіх компонентів
виявляються однаковими. На рис. показано вікно кнопок калькулятора (сіткова
компоновка). При зміні розмірів вікна кнопки автоматично збільшуються або
зменшуються, причому розміри всіх кнопок залишаються однаковими.
Необхідна кількість рядів і стовпців вказується в
конструкторі GridLayout:
panel.setLayout(new GridLayout(4, 4));
Компоненти вводяться послідовно рядок за рядком.
Приклад в книзі «Хорстманн. Java. Бібліотека
професіонала, том 1. Основи. 10-е видання », стор
572. (corejava10.zip\corejava\v1ch12\calculator)
Звичайний калькулятор.
Компонування без диспетчера
Іноді потрібно просто розташувати який-небудь компонент в потрібному місці, не
вдаючись до допомоги диспетчера компонування. Такий процес називається
абсолютним розташуванням.
Щоб розташувати компонент в потрібному місці необхідно зробити наведене
нижче.
frame.setLayout(null); //прибрати диспетчер компонування
JButton ok = new JButton("OK");
frame.add(ok);
ok.setBounds(10,10,30,15); //координати і розміри компонента

5.3. Введення тексту


Для вводу та редагування тексту передбачені два компоненти: текстове поле типу
JTextField та текстова область типу JTextArea. У текстовому полі можна ввести
лише один рядок тексту, а в текстовій області - кілька рядків. Поле типу
JPasswordField приймає текстовий рядок, не відображається її вміст.
Усі ці класи розширюють клас абстрактний JTextComponent. У цьому класі
реалізовані методи, що дозволяють встановити текст або отримати його з
текстового поля чи області.
Текстові поля
Текстове поле розміщується на панелях або в іншому контейнері аналогічно
кнопкам.
JPanel panel = new JPanel();
JTextField textField = new JTextField("Default input", 20);
panel.add(textField);
Текстове поле ініціалізоване рядком "DefaultInput". Другий параметр конструктора
задає видиму довжину рядка в символах. Символи - не дуже точна одиниця
виміру. На практиці така одиниця вимірювання не зовсім придатна, і тому довжину
рядка збільшують на один-два символи. Задане число символів вважається лише
бажаною довжиною. Диспетчер компоновки може змінити довжину поля.
Користувач може набирати довші рядки, якщо текст виходить за межі текстого
поля,відбудеться прокрутка його вмісту. Під час виконання можна змінити розмір
поля, викликавши метод setColumns().
ПОРАДА. Після зміни розмірів текстового поля методом setColumns() слід
викликати метод revalidate():
textField.setColumns(10);
panel.revalidate();
Метод revalidate() відноситься до класу JComponent. Якщо потрібно змінити
розміри компонентів у контейнері типу JFrame, слід викликати метод validate(),
оскільки клас JFrame не є виробничим з класу JComponent.
Текст в текстовому полі можно змінити в будь-який момент, викликавши метод
setText():
textField.setText("Привіт!");
Визначити, який саме текст міститься в текстовому полі, можна за допомогою
методу getText(), який повертає текст, який був набраний користувачем. Відрізати
зайві пробіли на початку та в кінці тексту можна методом trim()
String text = textField.getText().trim();
Написи (мітки)
Мітки це компоненти, що зберігають текст написів. Вони не мають рамок а також
не реагують на введення даних користувачем. Мітки можуть використовуватися
для позначення компонентів. Наприклад, текстові компоненти не мають позначок,
які дозволили б їх розрізняти. Щоб позначити компонент, який не має свого
ідентифікатора, необхідно виконати наступні дії.
1. Створити компонент типу JLabel, що містить заданий текст.
2. Розташувати його досить близько до компоненту, щоб користувач міг ясно
бачити, що дана мітка відноситься саме до цього компоненту.
Конструктор класу JLabel дозволяє задати текст або піктограму, а також вирівняти
вміст компонента. В інтерфейсі SwingConstants визначено кілька корисних
констант, в тому числі LEFT, RIGHT, CENTER, NORTH, EAST і т.п. Клас JLabel
реалізує цей інтерфейс.
JLabel label = new JLabel("User name:", SwingConstants.RIGHT);
або
JLabel label = new JLabel("User name:", JLabel.RIGHT);
За допомогою методів setText() і setIcon() можна задати текст напису і піктограму
для мітки під час виконання.
Поля для введення пароля
Поля для введення пароля являють собою особливий вид текстових полів. Кожен
символ в паролі замінюється при відображенні echo-символом, зазвичай зірочкою
(*). Клас JPasswordField реалізує таке текстове поле.
Поле для введення пароля служить ще одним прикладом шаблону MVC. Для
зберігання даних застосовується та ж сама модель, що і для звичайного
текстового поля, але вид (уявлення, view) цього поля змінено, замінюючи всі
символи пароля echo -символами.
Текстові області
Коли виникає потреба ввести кілька текстових рядків застосовується компонент
JTextArea. Користувач може вводити скільки завгодно тексту, розділяючи його
рядки натисканням клавіші <Enter>. Кожен рядок завершується символом '\n', як
це передбачено в Java.
У конструкторі JTextArea вказується кількість рядків і їх довжина (символах):
textArea = new JTextArea(8,40); //8 рядків по 40 стовпців
Користувач не обмежений кількістю введених рядків і їх довжиною. Якщо довжина
рядка або число рядків вийде за межі заданих параметрів, текст буде
прокручуватися в вікні. Для зміни довжини рядків можна викликати метод
setColumns(), а для зміни їх кількості - метод setRows(). Ці параметри задають
лише рекомендовані розміри, а диспетчер компонування може самостійно
збільшувати або зменшувати розміри текстової області.
Можна встановити автоматичний перенос рядка наступним чином:
textArea.setLineWrap(true); //в довгих рядках - перенос
Автоматичне перенесення рядка проявляється лише візуально.
Панелі прокрутки
У бібліотеці Swing текстова область не забезпечується смугами прокрутки. Якщо
вони потрібні, текстову область слід ввести на панелі прокрутки
textArea = new JTextArea(8,40);
JScrollPane scrollPane = new JScrollPane(textArea);
Тепер панель прокрутки управляє поданням текстової області. Смуги прокрутки
з'являються автоматично, коли текст виходить за межі відведеної для нього
області, і зникають, коли решта тексту видаляється. Прикладна програма не
повинна обробляти події, пов'язані з прокруткою.
Це універсальний механізм, який придатний для будь-якого компонента, а не
тільки для текстових областей. Щоб ввести смуги прокрутки в компонент,
компонент досить розмістити на панелі прокрутки.
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання », стор 581. (corejava10.zip\corejava\v1ch12\text)
Демонструються різні текстові компоненти: текстове поле, поле для введення
пароля і текстова область з смугами прокрутки. Текстове поле і поле для введення
пароля забезпечені мітками.
5.4. Компоненти для вибору із різних варіантів
У багатьох випадках потрібно вибір дії користувача з кінцевого числа варіантів. Ці
варіанти можуть бути представлені екранними кнопками або списком обираних
елементів. Розглянемо порядок програмування таких компонентів інтерфейсу, як
прапорці, кнопки-перемикачі, списки і регульовані повзунки.
Прапорці
Якщо дані зводяться до двозначної логіки на кшталт «Так» або «Ні», то для їх
введення можна скористатися прапорцем. Клацання миші на компоненті
встановлює або скидає прапорець. Встановити або скинути прапорець можна
також за допомогою клавіші пробілу, натиснувши її в той момент, коли на даному
компоненті знаходиться фокус введення.
Прапорці супроводжуються мітками, які вказують призначення. Текст мітки
задається в конструкторі:
JCheckBox bold = new JCheckBox("Bold");
Метод setSelected() встановлює або скидає прапорець:
bold.setSelected(true);
Метод isSelected() дозволяє визначити поточний стан кожного прапорця.
З компонентом можна зв'язати об'єкт приймача подій.
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання », стор 584.( corejava10.zip\corejava\v1ch12\checkBox)
Показано просте вікно прикладної програми з двома прапорцями, один з яких
включає і відключає курсив, а інший - напівжирний шрифт шрифту.
У прикладі для обох прапорців передбачений один і той же приймач дій:
ActionListener listener = ...
bold.addActionListener(listener);
italic.addActionListener(listener);
У методі actionPerformed () обробника подій запитується поточний стан прапорців
bold і italic, а потім встановлюється накреслення шрифту
public void actionPerformed (ActionEvent event) {
int mode = 0;
if (bold.isSelected()) mode += Font.BOLD;
if (italic.isSelected()) mode += Font.ITALIC;
label.setFont(new Font( "Serif", mode, FONTSIZE));
}

Кнопки-перемикачі
У попередньому прикладі прапорці можуть встановлюватися незалежно один від
іншого. Але часто потрібно вибрати тільки один із запропонованих варіантів. Таку
групу прапорців часто називають групою кнопок-перемикачів - при натисканні
однієї з таких кнопок раніше натиснута кнопка повертається в початковий стан.
Бібліотека Swing дозволяє легко реалізувати групи кнопок-перемикачів. Для цього
потрібно створити по одному об'єкту типу ButtonGroup на кожну групу. Потім в
групу кнопок-перемикачів слід ввести об'єкти типу JRadioButton.
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання », стор 587.(corejava10.zip\corejava\v1ch12\radioButton)
Програма з групою кнопок-перемикачів. Користувач може вибрати розмір шрифту -
Small, Medium, Large і Extra large.
ButtonGroup group = new ButtonGroup();
JRadioButton smallButton = new JRadioButton("Small", false);
group.add(smallButton);
JRadioButton mediumButton = new JRadioButton("Medium", true);
group.add(mediumButton);

Комбіновані списки
Якщо варіантів вибору занадто багато, то слід скористатися списком, що
розкривається. Якщо користувач клацне на цьому компоненті, розкриється список,
з якого він може вибрати один з елементів.
Якщо список, що розкривається, є редагованим, то обраний з нього елемент
можна поправити як в звичайному тестовому поле. Редагований список, що
розкривається, об'єднує властивості текстового поля і можливості вибору та
називається комбінованим. Компоненти комбінованих списків створюються
засобами класу JComboBox. Починаючи
з версії Java SE 7, клас JComboBox є
узагальненим: комбінований список типу
JComboBox<String> складається з
строкових об'єктів типу String, а
комбінований список типу
JComboBox<Integer> - з цілочисельних
значень.
Щоб зробити список, що розкривається
редагованим (комбінованим), слід
викликати метод setEditable(). Зміни
вносяться тільки в поточний елемент
списку. Перелік варіантів вибору
залишається колишнім.
Обраний варіант в вихідному або відредагованому вигляді можна отримати за
допомогою методу getSelectedItem().
Якщо списку не редагований, то для отримання обраного варіанту потрібного типу
краще зробити наступний виклик:
combo.getItemAt(combo.getSelectedlndex())
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання », стор 595 (corejava10.zip\corejava\v1ch12\comboBox)
У прикладі у користувача є можливість вибрати стиль шрифту із заданого списку.
JComboBox <String> faceCombo = new JComboBox<>();
faceCombo.addltem("Serif");
faceCombo.addltem("SansSerif");.
Коли користувач вибирає потрібний варіант з комбінованого списку, цей компонент
ініціює подію. В обробнику події, щоб визначити варіант, обраний зі списку, слід
викликати метод getSource() з даною подією в якості параметра. Цей метод
повертає посилання на список, який є джерелом події. Потім слід викликати метод
getSelectedltem (), який повертає варіант, обраний зі списку.
НА ЗАМІТКУ! Щоб показати звичайний список, елементи якого постійно
відображалися на екрані скористайтесь компонентом JList.
Регульовані повзунки
Комбіновані списки дають можливість робити вибір з дискретного ряду варіантів. А
регульовані повзунки дозволяють вибрати конкретне значення в заданих межах,
наприклад, будь-яке число в межах від 1 до 100. Створення повзунка:
JSlider slider = new JSlider(min, max, initialValue) ;.
Коли користувач переміщує повзунок, обиране значення в компоненті змінюється в
межах від мінімального до максимального. Приймачі подій від регульованого
повзунка отримують подія типу ChangeEvent.
Щоб отримувати повідомлення при переміщенні повзунка, слід створити і
зареєструвати об'єкт класу, що реалізовує інтерфейс ChangeListener. В
інтерфейсі оголошена функція stateChanged(ChangeEvent e). Для реєстрації
викликати метод addChangeListener().
Приклад «Хорстманн. Java. Бібліотека професіонала, том 1. Основи. 10-е
видання », стор 599.( corejava10.zip\corejava\v1ch12\slider) Регульовані повзунки
різних видів
5.5. Меню
У бібліотеці Swing передбачені спадаючі меню. Рядок меню у верхній частині вікна
містить назви спадаючих меню. Клацаючи на такому імені кнопкою миші,
користувач відкриває меню, що складається з пунктів і підміню. Якщо користувач
клацне на пункті меню, все меню закриються і програмою буде відправлено
відповідне повідомлення.
Створення меню
Створюється меню наступним чином:
JMenuBar menuBar = new JMenuBar();
Рядок меню - це звичайний компонент, який
можна розташувати де завгодно. Як правило,
вона розташовується у верхній частині фрейма
за допомогою методу setJMenuBar():
frame.setJMenuBar(menuBar);
Для кожного меню створюється свій об'єкт в такий спосіб:
JMenu editMenu = new JMenu("Edit");
Меню верхнього рівня розміщуються до рядка меню:
menuBar.add(editMenu);
Потім в об'єкт меню вводяться пункти, роздільники і підміню:
JMenuItem pasteltem = new JMenuItem ( "Paste");
editMenu.add(pasteltem);
editMenu.addSeparator();
JMenu optionsMenu = ...; // підміню
editMenu.add(optionsMenu);
Для кожного пункту меню слід визначити обробник:
ActionListener listener = ...;
pasteltem.addActionListener(listener);
Є зручний метод JMenu.add(String s), що дозволяє додавати новий пункт в кінці
меню. Цей метод повертає створений пункт меню, для якого можна легко задати
обробник:
JMenuItem pasteltem = editMenu.add("Paste");
pasteltem.addActionListener(listener);
Пункти меню часто зв'язуються з командами (об'єктами типу Action), які можуть
активізувати інші елементи призначеного для користувача інтерфейсу (кнопки,
комбінації клавіш). Визначається клас, який реалізує інтерфейс Action. Зазвичай
він розширює клас AbstractAction. У конструкторі AbstractAction вказується мітка
пункту меню і перевизначається метод actionPerformed(), що дозволяє
реалізувати обробку події, пов'язаного з цим пунктом меню.
// "Exit" -пункт меню
Action exitAction = new AbstractAction("Exit") {
public void actionPerformed(ActionEvent event) {
// код виконуваного дії
System.exit(0);
}
};
Потім об'єкт типу Action вводиться в меню наступним чином:
JMenuItem exitltem = fileMenu.add(exitAction);
У підсумку новий пункт вводиться в меню по імені дії. Об'єкт цієї дії стає
оброблювачем. Такий прийом дозволяє замінити такі рядки коду:
JMenuItem exitltem = new JMenuItem(exitAction);
fileMenu.add(exitltem);
Піктограми в пунктах меню
Як і екранні кнопки, меню можуть мати текстову мітку, піктограму або і те й інше.
Піктограму можна вказати в конструкторі JMenuItem, або задати за допомогою
методу setlcon(), або пов'язати з дією.
Пункти меню з прапорцями і кнопками-перемикачами
Пункти меню можуть також містити прапорці або кнопки-перемикачі. Коли
користувач клацає кнопкою миші на пункті меню, прапорець автоматично
встановлюється або скидається, а стан кнопки-перемикача змінюється відповідно
до обраного пунктом. Створення пункту меню з прапорцем:
JCheckBoxMenuItem readonlyltem =
new JCheckBoxMenuItem("Read-only");
optionsMenu.add(readonlyltem);
Для введення в меню кнопок-перемикачів в меню слід додати групу кнопок-
перемикачів. Вибирається одна з таких кнопок, інші відключаються.
ButtonGroup group = new ButtonGroup();
JRadioButtonMenuItem insertltem =
new JRadioButtonMenuItem ( "Insert");
insertltem.setSelected(true);
JRadioButtonMenuItem overtypeltem =
new JRadioButtonMenuItem ( "Overtype");
group.add(insertltem);
group.add(overtypeltem);
optionsMenu.add(insertltem);
optionsMenu.add(overtypeltem);
Спливаючі меню
Спливаючі або контекстні меню не пов'язані з рядком меню а з'являються в
довільно обраному місці на екрані.
Спливаюче меню створюється так само, як і
звичайне меню, за винятком того, що у нього
відсутній заголовок.
JPopupMenu popup = new JPopupMenu();
Пункти додаються як зазвичай:
JMenuItem item = new
JMenuItem(Cut");
item.addActionListener(listener);
popup.add(item);
Спливаюче меню слід явним чином виводити на екран за допомогою методу
show(). При виклику цього методу (в обробнику події) задається батьківський
компонент і розташування спливаючого меню в його системі координат:
popup.show(panel, х, у);
Спливаюче меню відображається на екрані, коли користувач клацає на спеціально
призначеній для цього кнопці. Як правило, права кнопка миші.
Для спливання меню після клацання кнопкою миші викликається наступний метод:
component.setComponentPopupMenu(popup);
Щоб похідний компонент успадковував меню батьківського компонента, досить
зробити наступний виклик:
child.setlnheritsPopupMenu(true);
Клавіші швидкого доступу та оперативні клавіші
Пункти меню зручно вибирати за допомогою клавіш швидкого доступу. Зв'язати
пункт меню з клавішею швидкого доступу можна, задавши цю клавішу в
конструкторі:
JMenuItem aboutltem = new JMenuItem("About",'A');
Буква, відповідна клавіші швидкого доступу, виділяється підкресленням. Тепер для
вибору пункту меню користувачеві досить натиснути клавішу <А>.
Маючи в розпорядженні об'єкт типу Action, можна призначити клавішу швидкого
доступу наступним чином:
cutAction.putValue(Action.MNEMONIC_KEY, new Integer('A'));
Щоб зв'язати якусь клавішу з меню в цілому,
слід викликати метод setMnemonic():
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic('H');
Тепер, щоб зробити вибір з рядка меню, досить
натиснути клавішу <Alt> разом з клавішею
призначеної літери: щоб вибрати меню Help,
слід натиснути комбінацію клавіш <Alt+H>.
Клавіші швидкого доступу дозволяють
вибрати пункт в уже відкритому меню.
Оперативні клавіші дозволяють вибрати
пункт, не відкриваючи меню. У багатьох
прикладних програмах передбачені комбінації
клавіш <Ctrl+O> і <Ctrl+S> для пунктів Open і
Save меню File. Для зв'язування оперативних
клавіш з пунктом меню служить метод
setAccelerator(), якому в якості параметра
передається об'єкт типу Keystroke.
openltem.setAccelerator(Keystroke.getKeyStroke("Ctrl О"));
Оперативні клавіші не відкривають меню, а тільки ініціюють подія, пов'язану із
зазначеним пунктом меню.
Якщо оперативні клавіші призначені для пункту меню, то відповідна комбінація
клавіш автоматично відображається в меню.
Відображення або приховування доступу до пунктів меню
Іноді деякі пункти меню повинні вибиратися лише в певному контексті. Так, якщо
документ відкритий лише для читання, то пункт меню Save не має сенсу. Тому
треба тимчасово заборонити доступ до деяких пунктів меню. Заборонений пункт
меню зазвичай виділений світло-сірим кольором як недоступний.
З метою дозволити або заборонити доступ до пунктів меню викликається метод
setEnabled():
saveltem.setEnabled(false);
Приклад «Хорстманн. Java. Бібліотека професіонала, том 1. Основи. 10-е
видання », стор 613. (corejava10.zip\corejava\v1ch12\menu) У прикладі
демонструються вкладені меню, недоступні пункти меню, прапорці та кнопки-
перемикачі в пунктах меню, а також клавіші швидкого доступу і оперативні клавіші
вибору пунктів меню.
Панелі інструментів
Панель інструментів являє собою ряд кнопок,
що забезпечують швидкий доступ до найбільш
часто використовуваних команд. Панель
інструментів відрізняється тим, що її можна
перетягувати на будь-яку з чотирьох сторін
фрейма.
Панель інструментів може бути навіть
відокремленою від фрейма. Тоді вона міститься
у власному фрейму.
НА ЗАМІТКУ! Перетягування панелі інструментів
можливо тільки разі розміщення в контейнері з
диспетчером компонування, що підтримує
розташування компонентів в північній, південній,
східній і західній областях фрейма.

Створення панелі і додавання до неї


компоненти:
JToolBar bar = new JToolBar(); // new
JToolBar(titlestring);
bar.add(blueButton);
titlestring - заголовок панелі, що з'явиться, коли панель буде відокремлена від
фрейма.
У класі JToolBar є методи для введення дії, представленої об'єктом типу Action:
bar.add(blueAction);
Піктограма, відповідна такому об'єкту, відображається на панелі інструментів.
Групи кнопок можна відокремлювати один від одного за допомогою роздільників:
bar.addSeparator();
Зазвичай панель інструментів розміщується в контейнері, як показано нижче:
add(bar, BorderLayout.NORTH);
На панелі інструментів можна розташувати не тільки кнопки, але і інші компоненти,
наприклад комбінований список.
Спливаючі підказки
У панелей інструментів є суттєвий недолік: за зовнішнім виглядом кнопки важко
здогадатися про її призначення. Як вихід із цього становища були винайдені
спливаючі підказки, які з'являються на екрані, коли курсор наводиться на екранну
кнопку. Текст підказки відображається в зафарбованому прямокутнику. Коли
курсор відводиться від кнопки, підказка зникає.
У бібліотеці Swing можна вводити спливаючі підказки в будь-який об'єкт типу
JComponent методом setToolTipText ():
exitButon.SetToolTipText("Exit");
Якщо скористатися об'єктами типу Action, то підказка зв'язується з ключем
SHORT_DESCRIPTION:
exitAction.putValue(Action.SHORT_DESCRIPTION, "Exit");
Приклад «Хорстманн. Java. Бібліотека професіонала, том 1. Основи. 10-е
видання », стор 619. (corejava10.zip\corejava\v1ch12\toolbar) У прикладі
демонструються введення одних і тих же об'єктів типу Action в меню і на панелі
інструментів.
5.6. Розширені засоби компонування
В розглянутих досі прикладах для створення інтерфейсу застосовувалися тільки
диспетчери граничної, потокової і сіткової компоновки. Але для вирішення більш
складних завдань компонування GUI цього явно недостатньо. Перерахуємо
розширені засоби компонування GUI.
Починаючи з версії Java 1.0, до складу бібліотеки AWT входять засоби сітково-
контейнерного компонування (GridBagLayout) для розташування компонентів по
рядах і стовпцях. Його можна розглядати як диспетчер сіткового компонування без
обмежень, тобто. при сітково-контейнерному компонуванні ряди і стовпці можуть
мати змінні розміри. Щоб розташувати великий компонент, який не вміщується в
одній комірці, кілька суміжних осередків можна з'єднати разом. Такий диспетчер
компонування діє дуже гнучко, але в той же час він досить складний.
Диспетчер блокової компоновки (BoxLayout) бібліотеки Swing здійснює вкладення
багатьох панелей з горизонтальними і вертикальними розмірами в різних
поєднаннях, досягаючи такого ж результату, як і диспетчер сіткового компонування
(GridLayout). Але блокова компоновка не підходить для впорядкування сусідніх
компонентів як по вертикалі, так і по горизонталі.
У версії Java SE 1.4 була зроблена спроба знайти заміну сітково-контейнерного
компонування - так зване пружинне компонуванням. На практиці такий підхід
виявився занадто важким і заплутаним.
У 2005 році розробники NetBeans винайшли технологію Matisse, яка поєднує в
собі інструмент і диспетчер компонування (тепер вона називається Swing GUI
Builder). Розробники інтерфейсу застосовують інструмент Swing GUI Builder, щоб
розмістити компоненти в контейнері і вказати ті компоненти, за якими вони повинні
бути вирівняні. А інструмент переводить задум розробника в інструкції для
диспетчера груповий компонування. Це набагато зручніше, ніж написання коду
управління компоновкою вручну. Диспетчер груповий компонування увійшов до
складу Java SE6. Навіть якщо ви не користуєтеся NetBeans як IDE, можна
розробляти GUI в NetBeans, вставляючи отриманий в результаті код в обрану
вами IDE.
5.7. Діалогові вікна
До сих пір розглядалися тільки компоненти користувальницького інтерфейсу, які
перебували у вікні фрейму, створюваного в додатку. Але при розробці додатків
виникає потреба в окремих спливаючих діалогових вікнах, які повинні з'являтися
на екрані і забезпечувати обмін даними з користувачем.
Як і в більшості віконних систем, в AWT розрізняються модальні і немодальні
діалогові вікна. Модальні діалогові вікна не дають користувачеві можливості
одночасно працювати з іншими вікнами програми. Наприклад, при введенні файлу
користувач повинен спочатку вказати його ім'я. І тільки після того, як користувач
закриє модальное діалогове вікно, додаток почне виконувати операцію введення
файлу.
Немодального діалогове вікно дає користувачеві можливість одночасно вводити
дані як в цьому вікні, так і в інших областях програми. Прикладом такого вікна
служить панель інструментів. Вона постійно перебуває на своєму місці, і
користувач може одночасно взаємодіяти як з нею, так і з іншими вікнами.
Діалогові вікна для вибору різних варіантів
У бібліотеку Swing входить багато готових простих діалогових вікон, які
дозволяють вводити дані окремими фрагментами. Для цього в класі JOptionPane
є статичні методи:
showMessageDialog() Виводить на екран повідомлення і чекає до тих
пір, поки користувач не клацне на кнопці ОК
showConfirmDialog() Виводить на екран повідомлення і чекає від
користувача підтвердження (клацання на кнопці
ОК або Cancel)
showOptionDialog() Виводить на екран повідомлення і надає
користувачеві можливість вибору серед декількох
варіантів
showInputDialog() Виводить на екран повідомлення і поле, в якому
користувач повинен ввести дані
Діалогове вікно може містити додатковий компонент для введення даних. Цим
компонентом може бути текстове поле, в якому користувач вводить довільний
символьний рядок, або комбінований список, один з елементів якого користувач
повинен вибрати.
Піктограма в лівій частині діалогового вікна вибирається залежно від типу
повідомлення. Існують п'ять типів повідомлень: ERROR_MESSAGE,
INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE,
PLAIN_MESSAGE. Для повідомлення типу PLAIN_MESSAGE піктограма не
передбачена. А для кожного типу діалогових вікон можна вказувати свою власну
піктограму.
З кожним типом діалогових вікон можна пов'язати повідомлення, яке може бути
представлено символьним рядком, піктограмою, компонентом
користувальницького інтерфейсу або будь-яким іншим об'єктом. Відображення
повідомлень:
String Виводить символьний рядок
Icon Показує піктограму
Component Показує компонент
Object[] Виводить всі об'єкти з масиву, відображаючи їх один над
іншим
Будь-який інший об'єкт Викликає метод toString () і виводить отриману в
результаті символьний рядок
Найчастіше виводиться символьний рядок повідомлення. При відображенні в
діалоговому вікні об'єкта типу Component можна намалювати все, що завгодно,
викликавши метод paintComponent().
Зовнішній вигляд кнопок, розташованих в нижній частині діалогового вікна,
залежить від його типу, а також від типу варіантів. При виклику
showMessageDialog(), showInputDialog() - стандартні кнопки (ОК або ОК і
Cancel). У методі showConfirmDialog() можна вибрати один з чотирьох типів
варіантів: DEFAULT_OPTION, YES_NO_OPTION, YЕS_NO_СANCEL_OРТION,
OK_CANCEL_OPTION.
Статичні методи, призначені для створення діалогових вікон, повертають
перераховані нижче значення.
showMessageDialog() Значення, що повертається, відсутнє
showConfirmDialog() Ціле значення, відповідне вибраному варіанту
showOptionDialog() Ціле значення, відповідне вибраному варіанту
showInputDialog() Символьний рядок, введений або обраний
користувачем
Методи showConfirmDialog() і showOptionDialog() повертають ціле значення, що
позначає кнопку, на якій клацнув користувач. У діалоговому вікні для вибору різних
варіантів це числове значення є порядковим номером. Якщо замість вибору
варіанту користувач закрив діалогове вікно, повертається константа
CLOSED_OPTION. Kонстанти, використовувані в якості значень, що повертаються:
OK_OPTION, CANCEL_OPTION, YES_OPTION, NO_OPTION, CLOSED_OPTION.
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання », стор 651, (corejava10.zip\corejava\v1ch12\optionDialog).
На екран виводиться вікно з шістьма панелями кнопок. Якщо клацнути на кнопці
Show, з'явиться вибраний тип діалогового вікна.
Створення власних діалогових вікон
Можна створити діалогове вікно самостійно. Щоб реалізувати таке вікно, необхідно
створити підклас, похідний від класу JDialog. Цей процес не відрізняється від
створення головного вікна програми розширенням класу JFrame, потрібно зробити
наступне:
1. Викликати конструктор суперкласу JDialog в конструкторі діалогового вікна.
2. Ввести в своє діалогове вікно компоненти користувальницького інтерфейсу.
3. Ввести обробники подій, які виникають в даному вікні.
4. Встановити розміри діалогового вікна.
При виклику конструктора суперкласу слід вказати фрейм-власник, заголовок вікна
і ознаку модальності. Фрейм-власник управляє місцем відображення діалогового
вікна. Замість власника можна вказати null, і тоді діалогове вікно буде належати
прихованому фрейму.
Як правило, немодальні діалогові вікна служать для створення панелей
інструментів, до яких постійно відкритий доступ. Модальні діалогові вікна
змушують користувача ввести інформацію щоб продовжити роботу з додатком.
Приклад створення діалогового вікна:
public AboutDialog extends JDialog {
public AboutDialog(JFrame owner) {
super(owner, "About DialogTest", true);
add(new JLabel(
"<html><h1><i>Core Java</i></hl><hr>By C.Horstmann</html>"),
BorderLayout.CENTER);
JPanel panel = new JPanel();
JButton ok = new JButton("OK");
ok.addActionListener(event->setVisible(false));
panel.add(ok);
add(panel, BorderLayout.SOUTH);
setSize(250, 150);
}
}
Конструктор діалогового вікна вводить в нього мітки і кнопку, обробник подій від
кнопки і задає розміри вікна. Щоб відобразити діалогове вікно, потрібно створити
об'єкт діалогу і викликати метод setVisible():
JDialog dialog = new AboutDialog (this);
dialog.setVisible(true);
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання», стор 661, (corejava10.zip\corejava\v1ch12\dialog). У
прикладі демонструється застосування модального діалогового вікна,
створюваного самостійно. Діалогове вікно створюється тільки один раз, а потім
воно використовується повторно щоразу, коли користувач клацає на кнопці About,
як показано нижче.
if (dialog == null) // перший раз
dialog = new AboutDialog(this);
dialog.setVisible (true);
Коли користувач клацає на кнопці OK, діалогове вікно має закриватися. Така
реакція на дії користувача визначається в обробнику подій від кнопки ОК, як
випливає з наведеної нижче рядки коду.
ok.addActionListener(event -> setVisible(false));
Коли ж користувач закриває діалогове вікно, клацаючи на кнопці Close, воно
зникає з поля зору. Як і в класі JFrame, таку поведінку можна змінити за
допомогою методу setDefaultCloseOperation().
Обмін даними
Зазвичай діалогові вікна створюються для того,
щоб отримати інформацію від користувача.
Покажемо, як вводити дані в діалоговому вікні.
Діалогове вікно на рис. можна використовувати
для отримання імені користувача і пароля.
Після виведення діалогу на екран
(setVisible(true)) користувач повинен ввести
дані в зазначених полях і клацнути на кнопці
ОК або Cancel. У обробниках подій від обох
кнопок викликається метод setVisible(false). У більшості випадків потрібно знати,
чи підтвердив користувач запроваджені ним дані або відмовився від їх введення.
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання », стор 665, (corejava10.zip\corejava\v1ch12\dataExchange).
У прикладі, перш ніж звертатися до діалогового вікна в змінної ok встановлюється
логічне значення false. А логічне значення true присвоюється цій змінній в
обробнику подій від кнопки ОК.
НА ЗАМІТКУ! Передати дані з немодального діалогового вікна не так-то просто.
При відображенні вікна виклик методу setVisible(true) не призводить до
припинення виконання програми. Якщо користувач виконає маніпуляції над
елементами в немодальному діалоговому вікні і потім клацне на кнопці ОК, це
вікно має повідомити відповідний приймач подій в самій програмі.
Діалогові вікна для вибору файлів
У бібліотеці Swing є клас JFileChooser, що дозволяє відображати діалогове вікно
для поводження з файлами, що задовольняє потребам більшості додатків. Це
діалогове вікно завжди є модальним. Клас JFileChooser не унаслідується від
класу JDialog. Замість методу setvisible(true) для відображення діалогового вікна
при відкритті файлів викликається метод showOpenDialog(), а при збереженні
файлів - метод showSaveDialog(). Кнопка, що підтверджує вибір файлу,
автоматично позначається як Open або Save.
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, том 1.
Основи. 10-е видання », стор 675, (corejava10.zip\corejava\v1ch12\fileChooser)
Діалогові вікна для вибору кольору
У бібліотеці Swing, крім вікна для вибору файлів, передбачено подібне діалогове
вікно для вибору кольору. Воно реалізовано засобами класу JColorChooser. Як і
клас JFileChooser, клас JColorChooser є компонентом, а не діалоговим вікном. Він
містить методи, що дозволяють створювати діалогові вікна для вибору кольору.
Приклад в книзі «Хорстманн. Java. Бібліотека професіонала, тому 1.
Основи. 10-е видання », стор 682, (corejava10.zip\corejava\v1ch12\colorChooser).
У прикладі демонструються три види діалогових вікон.
Якщо клацнути на кнопці Modal, то відкриється модальное діалогове вікно, в якому
слід вибрати колір, перш ніж зробити що-небудь інше.
Якщо клацнути на кнопці Modeless, відкриється немодального діалогове вікно, але
внесені в колір зміни вступлять в дію тільки після закриття цього вікна клацанням
на кнопці ОК.
А якщо клацнути на кнопці Immediate, то відкриється немодального діалогове
вікно без екранних кнопок. І як тільки в ньому буде обраний новий колір, відразу ж
зміниться колір фону панелі.

You might also like