gadget59.ru лекции
Java · Swing · 24 слайда

ОАиП. Swing — первое знакомство. Графический интерфейс в Java

Swing — первое знакомство

Swing — библиотека Java для построения оконного графического интерфейса (GUI): окна, кнопки, поля ввода, списки и таблицы.

Swing входит в набор Java Foundation Classes (JFC), надстроен над более старым пакетом AWT и рисует свои компоненты сам, поэтому одинаково выглядит на Windows, macOS и Linux.

🪟 JFrame 📋 JList 📋 JComboBox 🎨 Layout Managers ⚡ EDT
Сегодня разберём: каркас Swing-приложения, менеджеры компоновки, списки JList и JComboBox, поток EDT. Все примеры — законченные программы.

Содержание урока

Swing или AWT: что выбрать

AWT (Abstract Window Toolkit) — первый оконный пакет Java. Его компоненты — это обёртки над «родными» элементами операционной системы (их называют тяжеловесными).

Swing свои компоненты рисует сам средствами Java (легковесные), поэтому даёт единый вид на всех платформах и намного больше готовых элементов.

ПризнакAWTSwing
Отрисовка компонентовсистемные (native) элементырисуются самой Java
Зависимость от платформывнешний вид зависит от ОСодинаковый вид везде
Набор компонентовбазовыйширокий (таблицы, деревья, списки)
Архитектура модель-представлениенетесть (модель отделена от вида)
Подключаемый вид (look and feel)нетесть

AWT vs Swing: практический вывод

На практике новый оконный код на чистом AWT почти не пишут: берут Swing, а из AWT используют только базовые классы, на которых Swing построен — Container, менеджеры компоновки, классы событий.

Полностью заменять Swing на AWT смысла нет.

Важно про современный Java

  • Swing по-прежнему поставляется в составе JDK и поддерживается.
  • Новые крупные интерфейсы часто делают на JavaFX или на вебе.
  • Апплеты (JApplet, Applet) — мёртвая ветка. Applet API объявлен устаревшим и намечен к удалению в JDK 17 (JEP 398). Браузеры давно не запускают апплеты.
Использовать Applet API не нужно — это устаревшая технология.

Каркас Swing-приложения

Любое окно Swing собирается из нескольких обязательных частей:

  1. JFrame — главное окно приложения с рамкой и заголовком (это контейнер верхнего уровня).
  2. Панель содержимого (content pane) — область внутри окна, куда добавляют компоненты.
  3. Менеджер компоновки (layout manager) — решает, как расположить компоненты внутри контейнера.
JFrame
→
Content Pane
→
Компоненты
→
Layout Manager

Минимальное окно Swing

Полный пример — окно с одной надписью:

import javax.swing.*; public class Hello { public static void main(String[] args) { // Весь код интерфейса выполняем в потоке обработки событий (EDT) SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Первое окно Swing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JLabel("Привет, Swing!", SwingConstants.CENTER)); frame.setSize(300, 120); frame.setLocationRelativeTo(null); // окно по центру экрана frame.setVisible(true); // без этой строки окно не появится }); } }
Откроется окно 300×120 по центру экрана с надписью «Привет, Swing!». В консоль ничего не выводится — это чисто оконная программа.

Две критичные строки

Для новичка важны две строки в примере:

  • frame.setVisible(true) — показывает окно. Без неё программа завершится, ничего не показав.
  • frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) — завершает приложение при закрытии окна. Иначе процесс останется висеть в памяти.
Про SwingUtilities.invokeLater поговорим отдельно на слайде 18 — это правило потока, а не украшение.

Менеджеры компоновки

Swing почти никогда не расставляет компоненты по пикселям вручную — за раскладку отвечает менеджер компоновки. Основные из них:

МенеджерКак располагает
FlowLayoutпо строке слева направо, с переносом
BorderLayoutпять зон: центр и четыре стороны (север, юг, запад, восток)
GridLayoutравные ячейки таблицы
BoxLayoutв один ряд по вертикали или горизонтали
GridBagLayoutгибкая сетка с разными размерами ячеек
У JFrame по умолчанию стоит BorderLayout. Поэтому в примере со списком мы положим список в центр, а строку статуса — на юг.

Список JList: модель, выбор, слушатель

JList — компонент Swing для показа списка элементов, из которых пользователь выбирает один или несколько.

Данные и способ их показа в нём разделены на три части, и это ключевая идея Swing:

  • Модель данных (ListModel) — что показывать: сами элементы списка. Для типовых случаев берут готовую DefaultListModel, в которую элементы добавляют и удаляют.
  • Модель выбора (ListSelectionModel) — что сейчас выделено. По умолчанию уже подключена DefaultListSelectionModel.
  • Отрисовщик (ListCellRenderer) — как рисовать элемент. Для строк подходит стандартный, менять его нужно только для своего оформления.

JList: три части в одной схеме

ListModel
→
JList
←
ListSelectionModel
JList
→
ListCellRenderer
→
Отображение
Такое разделение позволяет менять данные независимо от отображения. Модель отделена от вида — это архитектура «модель-представление».

JList: режимы выбора

У выбора есть три режима, их задают через setSelectionMode:

РежимЧто позволяет выделить
SINGLE_SELECTIONровно один элемент
SINGLE_INTERVAL_SELECTIONодин непрерывный диапазон
MULTIPLE_INTERVAL_SELECTIONлюбой набор элементов (режим по умолчанию)
Для получения выбранных значений используйте getSelectedValue() (одиночный режим) или getSelectedValuesList() (множественный).

JList: пример кода

Список языков программирования, под ним — строка с выбранным элементом:

import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.BorderLayout; public class ListDemo { public static void main(String[] args) { SwingUtilities.invokeLater(ListDemo::createUi); } private static void createUi() { // Модель данных: что показывать в списке DefaultListModel<String> model = new DefaultListModel<>(); model.addElement("Python"); model.addElement("Java"); model.addElement("Go"); model.addElement("Rust"); JList<String> list = new JList<>(model); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JLabel status = new JLabel("Ничего не выбрано"); list.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { // событие приходит дважды на один клик; берём только устоявшийся выбор if (!e.getValueIsAdjusting()) { String value = list.getSelectedValue(); status.setText("Выбрано: " + value); } } }); JFrame frame = new JFrame("Список языков"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JScrollPane(list), BorderLayout.CENTER); frame.add(status, BorderLayout.SOUTH); frame.setSize(300, 220); frame.setLocationRelativeTo(null); frame.setVisible(true); } }

JList: что произойдёт

Откроется окно со списком из четырёх языков. Если кликнуть по строке «Java», надпись внизу станет «Выбрано: Java», и в консоль выведется та же строка.

Здесь заметны два практических момента.
  • Список всегда кладут в JScrollPane — тогда при большом числе элементов появляется полоса прокрутки.
  • Проверка getValueIsAdjusting() отсекает промежуточные срабатывания. На один выбор событие приходит дважды — в начале и в конце, — иначе обработчик выполнится лишний раз.
Если разрешить множественный выбор (MULTIPLE_INTERVAL_SELECTION), выбранные элементы берут методом getSelectedValuesList() (доступен с Java 7). Для одиночного режима удобнее getSelectedValue().

ListSelectionListener: обработка выбора

Чтобы реагировать на выбор, к списку добавляют слушатель ListSelectionListener. Он вызывается каждый раз, когда меняется выделение.

list.addListSelectionListener(e -> { if (!e.getValueIsAdjusting()) { String selected = list.getSelectedValue(); System.out.println("Выбрано: " + selected); } });
Обратите внимание: в Java 8+ можно использовать лямбда-выражение вместо анонимного класса — код становится короче.

JList: частые ошибки

  • Список без прокрутки — JList не обёрнут в JScrollPane. При большом количестве элементов часть просто не видна.
  • Слушатель срабатывает дважды — забыли проверку getValueIsAdjusting().
  • Пустой список — забыли добавить элементы в модель или не передали модель в JList.
  • NullPointerException — getSelectedValue() возвращает null, если ничего не выбрано. Проверяйте на null.
  • Изменение UI из другого потока — вся работа с JList должна идти в EDT.

JList: что важно запомнить

  • ✅ JList — список элементов с возможностью выбора.
  • ✅ Данные хранятся в ListModel (обычно DefaultListModel).
  • ✅ Выделение управляется ListSelectionModel.
  • ✅ Режим выбора задаётся через setSelectionMode().
  • ✅ Реакция на выбор — через ListSelectionListener.
  • ✅ Всегда оборачивайте JList в JScrollPane.
  • ✅ Проверяйте getValueIsAdjusting() — иначе обработчик сработает дважды.
JList — базовый компонент для работы со списками. Понимание модели данных — ключ к работе с таблицами (JTable) и деревьями (JTree).

Выпадающий список JComboBox

Когда на экране мало места, а выбрать нужно один вариант, вместо JList берут JComboBox — выпадающий список. В свёрнутом виде он показывает один выбранный элемент, а остальные раскрываются по клику.

JComboBox
→
Один элемент
→
Раскрытие по клику
Компактный, экономит место, идеально подходит для выбора одного значения из небольшого набора.

JComboBox: пример кода

import javax.swing.*; import java.awt.FlowLayout; public class ComboDemo { public static void main(String[] args) { SwingUtilities.invokeLater(() -> { String[] items = {"Junior", "Middle", "Senior"}; JComboBox<String> combo = new JComboBox<>(items); // ActionListener срабатывает при выборе пункта combo.addActionListener(e -> System.out.println("Выбран уровень: " + combo.getSelectedItem())); JFrame frame = new JFrame("Выпадающий список"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new FlowLayout()); frame.add(new JLabel("Уровень:")); frame.add(combo); frame.setSize(320, 120); frame.setLocationRelativeTo(null); frame.setVisible(true); }); } }
В окне будет надпись «Уровень:» и рядом выпадающий список. При выборе пункта «Senior» в консоль выведется: Выбран уровень: Senior.

JList vs JComboBox: в чём разница

Разница в интенте, а не в устройстве: JComboBox тоже опирается на модель (ComboBoxModel, наследник ListModel).

КритерийJListJComboBox
Показ элементоввсе сразупо клику (выпадающий)
Место на экранемногомало
Множественный выборданет
Длинные спискиудобноне очень
Выбор одного значениядада — идеально
Модель данныхListModelComboBoxModel
JComboBox подходит для выбора одного значения из компактного перечня. JList показывает элементы сразу и удобен для множественного выбора и длинных списков.

Почему весь код в invokeLater

Swing не потокобезопасен: обращаться к его компонентам можно только из специального потока обработки событий (Event Dispatch Thread, EDT).

Поэтому построение окна оборачивают в SwingUtilities.invokeLater(...) — так код гарантированно выполнится в EDT.

SwingUtilities.invokeLater(() -> { // Весь код интерфейса — здесь // Этот блок выполнится в потоке EDT });
Отсюда практическое правило: долгую работу (запрос к сети, чтение большого файла) в EDT выполнять нельзя — интерфейс замрёт и перестанет отвечать.

SwingWorker для долгих задач

Долгую работу выносят в фоновый поток, обычно через класс SwingWorker, а результат возвращают в EDT для показа.

EDT
→
SwingWorker
→
Фоновый поток
→
Возврат в EDT
SwingWorker умеет выполнять работу в фоне и публиковать промежуточные результаты в EDT. Так интерфейс остаётся отзывчивым.

Если окно ведёт себя не так

Типичные проблемы и их причины:

  • Окно не появилось — забыли setVisible(true) или программа завершилась раньше, чем показала окно.
  • Компоненты налезают друг на друга или окно пустое — не задан менеджер компоновки или все компоненты попали в одну зону BorderLayout (по умолчанию — центр).
  • Список без прокрутки при большом числе элементов — JList не обёрнут в JScrollPane.
  • Интерфейс завис после нажатия — в EDT запущена долгая операция, её нужно вынести в фоновый поток.
Если окно не появилось — первым делом проверьте setVisible(true). Это самая частая ошибка новичка.

Выводы

  • ✅ Swing — библиотека Java для оконного GUI поверх AWT: рисует компоненты сама, поэтому даёт единый вид на всех платформах и богатый набор элементов.
  • ✅ Новый оконный код пишут на Swing, из AWT берут только базовые классы; апплеты (JApplet) — мёртвая ветка, Applet API намечен к удалению (deprecated for removal) с JDK 17.
  • ✅ В JList данные и выбор разделены: ListModel (чаще DefaultListModel) хранит элементы, ListSelectionModel — выделение; реагируют на выбор через ListSelectionListener с проверкой getValueIsAdjusting().
  • ✅ JComboBox — выпадающий выбор одного значения; JList — показ элементов сразу и множественный выбор, обычно внутри JScrollPane.
  • ✅ Весь код интерфейса выполняют в потоке EDT (SwingUtilities.invokeLater), а долгую работу выносят в фоновый поток.

Где применяется Swing и что учить дальше

Swing до сих пор держит десктопные инструменты Java:

  • Среды разработки семейства IntelliJ IDEA.
  • Клиенты баз данных.
  • Внутренние корпоративные приложения.

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

Что учить дальше: JTable (таблицы), JTree (деревья), JavaFX (современная альтернатива Swing), событийная модель и MVC-паттерн.