Графический интерфейс в Java: Swing и списки JList

Графический интерфейс в Java: Swing и списки JList Полезное

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

Ниже разберем, из чего собирается Swing-приложение (окно JFrame, панель содержимого, менеджеры компоновки), и подробно — работу со списками: обычным JList с моделью и обработкой выбора и выпадающим JComboBox. Все примеры — законченные программы, которые можно скопировать и запустить.

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

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

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

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

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

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

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

  • JFrame — главное окно приложения с рамкой и заголовком (это контейнер верхнего уровня).
  • панель содержимого (content pane) — область внутри окна, куда добавляют компоненты.
  • менеджер компоновки (layout manager) — решает, как расположить компоненты внутри контейнера.

Начнем с минимального полного примера — окна с одной надписью:

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!». В консоль ничего не выводится — это чисто оконная программа.

Две строки тут критичны для новичка: setVisible(true) показывает окно (без нее программа завершится, ничего не показав), а setDefaultCloseOperation(EXIT_ON_CLOSE) завершает приложение при закрытии окна (иначе процесс останется висеть в памяти).

Про SwingUtilities.invokeLater скажу отдельно ниже — это не украшение, а правило потока.

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

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

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

У JFrame по умолчанию стоит BorderLayout, поэтому в примере со списком ниже мы кладем список в центр, а строку статуса — на юг.

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

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

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

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

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

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

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);
                    System.out.println("Выбрано: " + 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);
    }
}

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

Выбрано: Java

Здесь заметны два практических момента. Первый: список всегда кладут в JScrollPane — тогда при большом числе элементов появляется полоса прокрутки. Второй: проверка getValueIsAdjusting() отсекает промежуточные срабатывания (на один выбор событие приходит дважды — в начале и в конце), иначе обработчик выполнится лишний раз.

Если разрешить множественный выбор (MULTIPLE_INTERVAL_SELECTION), выбранные элементы берут методом getSelectedValuesList(), который возвращает список значений (он доступен начиная с Java 7). Для одиночного режима удобнее getSelectedValue().

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

Когда на экране мало места, а выбрать нужно один вариант, вместо JList берут 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 в интенте, а не в устройстве: JComboBox тоже опирается на модель (ComboBoxModel, наследник ListModel) и подходит для выбора одного значения из компактного перечня; JList показывает элементы сразу и удобнее для множественного выбора и длинных списков.

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

Swing не потокобезопасен: обращаться к его компонентам можно только из специального потока обработки событий (Event Dispatch Thread, EDT). Поэтому построение окна оборачивают в SwingUtilities.invokeLater(...) — так код гарантированно выполнится в EDT.

Отсюда же практическое правило: долгую работу (запрос к сети, чтение большого файла) в EDT выполнять нельзя — интерфейс замрет и перестанет отвечать. Такую работу выносят в фоновый поток, обычно через класс SwingWorker, а результат возвращают в EDT для показа.

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

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

Выводы

  • 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 до сих пор держит десктопные инструменты Java: среды разработки семейства IntelliJ IDEA, клиенты баз данных, внутренние корпоративные приложения. Умение собрать окно, вывести данные списком и обработать выбор пользователя — базовый навык, который нужен и для настольных программ, и как ступень к пониманию событийной модели интерфейсов вообще.

Освойте тему на практике

Если хочется освоить Java системно — от синтаксиса и ООП до работы с интерфейсом и коллекциями, — посмотрите курс Java Developer. Basic. Оценить формат и уровень до старта помогают бесплатные открытые уроки Otus — живые занятия с преподавателями.

FAQ

Swing умер, стоит ли его учить в 2026 году? Swing по-прежнему входит в JDK и поддерживается, на нем работают крупные десктопные приложения. Для нового большого интерфейса чаще берут JavaFX или веб, но Swing остается рабочим инструментом и хорошей базой для понимания оконного GUI.

Чем JList отличается от JComboBox? JList показывает все элементы сразу и позволяет выбрать несколько; JComboBox в свернутом виде показывает один выбранный элемент, а остальные раскрывает по клику, и рассчитан на выбор одного значения.

Как в JList разрешить выбор нескольких элементов? Задать режим setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) и читать выделенное методом getSelectedValuesList().

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)