Swing — это набор инструментов для создания графических виджетов для Java . [1] Он является частью Oracle Java Foundation Classes (JFC) — API для предоставления графического пользовательского интерфейса (GUI) для программ Java.
Swing был разработан для предоставления более сложного набора компонентов GUI, чем более ранний Abstract Window Toolkit (AWT) . Swing обеспечивает внешний вид и поведение , которые эмулируют внешний вид и поведение нескольких платформ, а также поддерживает подключаемый внешний вид и поведение , который позволяет приложениям иметь внешний вид и поведение, не связанные с базовой платформой. Он имеет более мощные и гибкие компоненты, чем AWT. В дополнение к знакомым компонентам, таким как кнопки, флажки и метки, Swing предоставляет несколько расширенных компонентов, таких как панель с вкладками, панели прокрутки, деревья, таблицы и списки. [2]
В отличие от компонентов AWT, компоненты Swing не реализуются платформенно-зависимым кодом. Вместо этого они полностью написаны на Java и, следовательно, не зависят от платформы.
В декабре 2008 года компания Sun Microsystems (предшественник Oracle) выпустила фреймворк на основе CSS / FXML , который, по ее замыслу, должен был стать преемником Swing, под названием JavaFX . [3]
Internet Foundation Classes (IFC) — графическая библиотека для Java, изначально разработанная корпорацией Netscape Communications Corporation и впервые выпущенная 16 декабря 1996 года. 2 апреля 1997 года компании Sun Microsystems и Netscape Communications Corporation объявили о намерении объединить IFC с другими технологиями для формирования Java Foundation Classes . [4] Позднее «Java Foundation Classes» были переименованы в «Swing». [ необходимо разъяснение ]
Swing представил механизм, который позволил изменять внешний вид и поведение каждого компонента в приложении без внесения существенных изменений в код приложения. Введение поддержки подключаемого внешнего вида и поведения позволяет компонентам Swing эмулировать внешний вид собственных компонентов, сохраняя при этом преимущества независимости от платформы. Первоначально распространяемый как отдельно загружаемая библиотека, Swing был включен в состав Java Standard Edition с версии 1.2. [5] Классы и компоненты Swing содержатся в иерархии javax.swing
пакетов .
Разработка преемника Swing, JavaFX , началась в 2005 году, и он был официально представлен два года спустя на JavaOne 2007. [6] JavaFX был открыт в 2011 году, а в 2012 году он стал частью загрузки Oracle JDK. JavaFX заменяет Swing из-за нескольких преимуществ, включая меньший вес, наличие стилей CSS , изящные элементы управления дизайном и использование FXML и Scene Builder. [7] В 2018 году JavaFX был включен в состав OpenJDK в рамках проекта OpenJFX для ускорения темпов его разработки. [8]
В команду Java Client, которая отвечала за Swing, входили Джеймс Гослинг (архитектор), Рик Левенсон (менеджер), Эми Фаулер и Ханс Мюллер (технические руководители), Том Болл, Джефф Динкинс, Жорж Сааб, [9] Тим Принцинг, Джонни Канерва, а также Жанетт Ханг и Джим Грэм (2D-графика). [10]
Swing — это платформенно-независимый GUI- фреймворк « модель–представление–контроллер » для Java, который следует однопоточной модели программирования. [11] Кроме того, этот фреймворк обеспечивает уровень абстракции между структурой кода и графическим представлением GUI на основе Swing.
Swing не зависит от платформы, поскольку полностью написан на Java. Полную документацию по всем классам Swing можно найти в Java API Guide для версии 6 или в Java Platform Standard Edition 8 API Specification для версии 8.
Swing — это высокомодульная архитектура, которая позволяет «подключать» различные пользовательские реализации указанных интерфейсов фреймворка: пользователи могут предоставлять свои собственные пользовательские реализации этих компонентов для переопределения реализаций по умолчанию с помощью механизма наследования Java через LookAndFeel
.
Swing — это компонентный фреймворк , все компоненты которого в конечном итоге являются производными от JComponent
класса. Объекты Swing асинхронно запускают события, имеют привязанные свойства и отвечают на документированный набор методов, специфичных для компонента. Компоненты Swing — это компоненты JavaBeans , соответствующие спецификации JavaBeans.
Сильная зависимость Swing от механизмов времени выполнения и косвенных шаблонов композиции позволяет ему реагировать во время выполнения на фундаментальные изменения в своих настройках. Например, приложение на основе Swing способно выполнять горячую замену своего пользовательского интерфейса во время выполнения. Кроме того, пользователи могут предоставлять собственную реализацию внешнего вида и поведения, что позволяет вносить единообразные изменения во внешний вид и поведение существующих приложений Swing без каких-либо программных изменений в код приложения.
Высокий уровень гибкости Swing отражается в его неотъемлемой способности переопределять элементы управления GUI собственной операционной системы хоста (ОС) для отображения себя. Swing «рисует» свои элементы управления с помощью API Java 2D, а не вызывает набор инструментов собственного пользовательского интерфейса. Таким образом, компонент Swing не имеет соответствующего компонента GUI собственной ОС и может свободно отображать себя любым способом, который возможен с помощью базовых графических GUI.
Однако в своей основе каждый компонент Swing опирается на контейнер AWT , поскольку (Swing) JComponent
расширяет контейнер (AWT). Это позволяет Swing подключаться к структуре управления графическим интерфейсом хостовой ОС, включая важнейшие сопоставления устройств/экранов и взаимодействия с пользователем, такие как нажатия клавиш или движения мыши. Swing просто «транспонирует» свою собственную (независимую от ОС) семантику поверх базовых (специфичных для ОС) компонентов. Так, например, каждый компонент Swing рисует свою визуализацию на графическом устройстве в ответ на вызов component.paint(), который определен в контейнере (AWT). Но в отличие от компонентов AWT, которые делегировали рисование своему «тяжеловесному» виджету ОС, компоненты Swing отвечают за свою собственную визуализацию.
Это транспонирование и разъединение не просто визуально, а распространяется на управление и применение Swing собственной независимой от ОС семантики для событий, запускаемых в иерархиях ее компонентов. В общем, архитектура Swing делегирует задачу отображения различных разновидностей семантики GUI ОС на простой, но обобщенный шаблон контейнеру AWT. Основываясь на этой обобщенной платформе, она устанавливает собственную богатую и сложную семантику GUI в форме модели JComponent
.
Библиотека Swing активно использует шаблон проектирования программного обеспечения модель–представление–контроллер [ 12] , который концептуально отделяет просматриваемые данные от элементов управления пользовательского интерфейса, через которые они просматриваются. Из-за этого большинство компонентов Swing имеют связанные модели (которые указаны в терминах интерфейсов Java ), и программисты могут использовать различные реализации по умолчанию или предоставлять свои собственные. Фреймворк предоставляет реализации по умолчанию интерфейсов моделей для всех своих конкретных компонентов. Типичное использование фреймворка Swing не требует создания пользовательских моделей, поскольку фреймворк предоставляет набор реализаций по умолчанию, которые прозрачно, по умолчанию, связаны с соответствующим дочерним классом в библиотеке Swing. В общем, только сложные компоненты, такие как таблицы, деревья и иногда списки, могут требовать пользовательских реализаций моделей вокруг структур данных, специфичных для приложения. Чтобы получить хорошее представление о потенциале, который делает возможной архитектура Swing, рассмотрим гипотетическую ситуацию, когда пользовательские модели для таблиц и списков являются обертками над службами DAO и/или EJB .JComponent
Обычно объекты модели компонента Swing отвечают за предоставление краткого интерфейса, определяющего запущенные события, и доступные свойства для (концептуальной) модели данных для использования связанным JComponent. Учитывая, что общий шаблон MVC является слабосвязанным шаблоном совместной объектной связи, модель предоставляет программные средства для присоединения прослушивателей событий к объекту модели данных. Эти события являются модельно-центричными (например, событие «вставлена строка» в табличной модели) и отображаются специализацией JComponent в значимое событие для компонента GUI.
Например, JTable
есть модель под названием TableModel
, описывающая интерфейс того, как таблица будет получать доступ к табличным данным. Реализация по умолчанию работает с двумерным массивом .
Компонент представления Swing JComponent — это объект, используемый для графического представления концептуального элемента управления GUI. Отличительной чертой Swing как фреймворка GUI является его зависимость от программно визуализируемых элементов управления GUI (в отличие от использования собственных элементов управления GUI хостовой ОС). До Java 6 Update 10 это различие было источником сложностей при смешивании элементов управления AWT, которые используют собственные элементы управления, с элементами управления Swing в GUI (см. Смешивание компонентов AWT и Swing ).
Наконец, с точки зрения визуальной композиции и управления Swing отдает предпочтение относительным макетам (которые определяют позиционные отношения между компонентами) в отличие от абсолютных макетов (которые определяют точное местоположение и размер компонентов). Этот уклон в сторону «текучего» визуального порядка обусловлен его происхождением из операционной среды апплета , которая обрамляла дизайн и разработку оригинального инструментария Java GUI. (Концептуально этот взгляд на управление макетом очень похож на тот, который информирует об отображении HTML-контента в браузерах, и решает тот же набор проблем, который мотивировал первый.)
Начиная с ранних версий Java, часть Abstract Window Toolkit (AWT) предоставляла платформенно-независимые API для компонентов пользовательского интерфейса. В AWT каждый компонент визуализируется и контролируется собственным компонентом-одноранговым компонентом, специфичным для базовой оконной системы.
Напротив, компоненты Swing часто описываются как легкие , поскольку они не требуют выделения собственных ресурсов в оконном инструментарии операционной системы. Компоненты AWT называются тяжеловесными компонентами . [13]
Большая часть API Swing, как правило, является дополнительным расширением AWT, а не прямой заменой. Фактически, каждый облегченный интерфейс Swing в конечном итоге существует внутри тяжеловесного компонента AWT, поскольку все компоненты верхнего уровня в Swing ( JApplet
, JDialog
, JFrame
, и JWindow
) расширяют контейнер верхнего уровня AWT. До Java 6 Update 10 использование как облегченных, так и тяжеловесных компонентов в одном окне, как правило, не поощрялось из-за несовместимости Z-порядка . Однако в более поздних версиях Java эти проблемы были исправлены, и теперь компоненты Swing и AWT можно использовать в одном GUI без проблем с Z-порядком.
Основная функциональность рендеринга, используемая Swing для отрисовки своих облегченных компонентов, предоставляется Java 2D , еще одной частью JFC.
Этот раздел может содержать материал, не относящийся к теме статьи . ( Май 2012 ) |
Standard Widget Toolkit (SWT) — это конкурирующий набор инструментов, изначально разработанный IBM и в настоящее время поддерживаемый сообществом Eclipse . Реализация SWT имеет больше общего с тяжеловесными компонентами AWT. Это дает такие преимущества, как более точная точность с базовым собственным набором инструментов для работы с окнами, за счет увеличения воздействия на собственную платформу в модели программирования.
Были серьезные дебаты и предположения о производительности SWT по сравнению со Swing; некоторые намекали, что сильная зависимость SWT от JNI сделает его медленнее, когда компоненту GUI и Java нужно обмениваться данными, но быстрее при рендеринге, когда модель данных загружена в GUI, но это не было подтверждено ни в том, ни в другом случае. [14] Довольно тщательный набор тестов в 2005 году пришел к выводу, что ни Swing, ни SWT явно не превзошли друг друга в общем случае. [15]
В этом примере приложения Swing создается одно окно с надписью «Hello, world!» внутри:
// Hello.java (Java SE 8) импорт javax.swing.* ; public class Hello extends JFrame { public Hello () { super ( "Привет, мир" ); setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE ) ; add ( new JLabel ( "Привет, мир!" ) ); pack ()); setVisible ( true ); } public static void main ( String [] args ) { SwingUtilities . invokeLater ( Hello :: new ); } }
Первый import
включает в себя все публичные классы и интерфейсы из javax.swing
пакета.
Класс реализует окно Hello
со строкой заголовка и кнопкой закрытия .extends
JFrame
JFrame
Конструктор инициализирует фрейм, сначала вызывая конструктор суперкласса, передавая параметр Hello()
,"Hello World"
который используется в качестве заголовка окна. Затем он вызывает setDefaultCloseOperation(int)
метод, унаследованный от , JFrame
чтобы задать операцию по умолчанию, когда выбран элемент управления «закрыть» в строке заголовка WindowConstants.EXIT_ON_CLOSE
– это приводит к тому, что JFrame
ликвидируется при закрытии фрейма (в отличие от простого скрытия), что позволяет виртуальной машине Java выйти и завершить программу. Затем JLabel
создается для строки «Hello, world!» и вызывается add(Component)
метод, унаследованный от Container
суперкласса, для добавления метки к фрейму. Метод, унаследованный от суперкласса, вызывается для изменения размера окна и размещения его содержимого. Метод, унаследованный от pack()
суперкласса , вызывается с логическим параметром , что приводит к отображению фрейма.Window
setVisible(boolean)
Component
true
Метод main()
вызывается виртуальной машиной Java при запуске программы. Он создает новый Hello
фрейм. Код использует invokeLater(Runnable)
метод для вызова конструктора из потока диспетчеризации событий AWT , чтобы гарантировать выполнение кода потокобезопасным способом . После отображения фрейма выход из main
метода не приводит к завершению программы, поскольку поток диспетчеризации событий остается активным до тех пор, пока все окна верхнего уровня Swing не будут удалены.
Ниже приведена довольно простая программа на основе Swing. Она отображает окно (a JFrame
), содержащее метку и кнопку.
import java.awt.FlowLayout ; import javax.swing.JButton ; import javax.swing.JFrame ; import javax.swing.JLabel ; import javax.swing.WindowConstants ; import javax.swing.SwingUtilities ; public class SwingExample implements Runnable { private JFrame f ; public SwingExample () { // Создаем окно f = new JFrame ( "Hello World!" ); // Устанавливаем поведение при закрытии окна f .setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE ); // Добавляем менеджер макетов, чтобы кнопка не размещалась поверх метки f .setLayout(new FlowLayout ( ) ) ; // Добавляем метку и кнопку f .add ( new JLabel ( " Hello, world!" ) ); f . добавить ( new JButton ( "Нажми меня!" )); } @Override public void run () { // Располагаем компоненты внутри окна f . pack (); // По умолчанию окно не видимо. Сделаем его видимым. f . setVisible ( true ); } public static void main ( String [] args ) { // Планирует запуск приложения в нужное время в очереди событий. SwingUtilities . invokeLater ( new SwingExample ()); } }
Обратите внимание, как все инстанцирование и обработка компонентов Swing выполняются путем создания экземпляра класса, который реализует интерфейс Runnable. Затем он запускается в Event Dispatch Thread с использованием метода SwingUtilities.invokeLater(Runnable)
), созданного в методе main (см. Swing и безопасность потоков ). Хотя код Swing можно запустить без использования этой техники (например, не реализуя Runnable и переместив все команды из метода run в метод main), это считается хорошим тоном, поскольку Swing не является потокобезопасным , что означает, что вызов ресурсов из нескольких потоков может привести к помехам потоков и ошибкам согласованности памяти. [16]
Текстовые поля позволяют пользователям вводить текст или данные в ваше приложение. Создание текстового поля в Swing просто — создайте экземпляр объекта JTextField и добавьте его в контейнер.
импорт javax.swing.* ; public class TextFieldExample { public static void main ( String [] args ) { // Создаем JFrame JFrame frame = new JFrame ( "Пример текстового поля" ); // Создаем JTextField JTextField textField = new JTextField ( 20 ); // Добавляем текстовое поле в фрейм JFrame . add ( textField ); // Устанавливаем размер JFrame и делаем его видимым frame.setSize ( 300 , 200 ) ; frame.setVisible ( true ) ; } }
Улучшение функциональности в текстовых полях улучшает взаимодействие с пользователем. Присоединяя интерфейсы DocumentListener, вы можете динамически отслеживать изменения в текстовом содержимом, обеспечивая проверку, форматирование или автоматическое завершение входных данных в реальном времени.
Проверка ввода текстового поля имеет решающее значение для обеспечения целостности данных и предотвращения ошибок. Swing предоставляет несколько методов проверки, включая регулярные выражения, маски ввода или пользовательскую логику проверки. Реализуя интерфейсы InputVerifier, вы можете определить определенные правила проверки и предложить пользователям немедленную обратную связь, если ввод недействителен. [17]
В этом примере пусть javax.swing.JFrame будет суперклассом и добавим к нему наши собственные виджеты (в данном случае JButton).
импорт javax.swing.JFrame ; импорт javax.swing.JButton ; импорт javax.swing.JOptionPane ; импорт javax.swing.SwingUtilities ; импорт java.awt.event.ActionListener ; импорт java.awt.event.ActionEvent ; public class Sample расширяет JFrame { private final JButton b = new JButton (); public Sample ( ) { super ( ); this.setTitle ( " HelloApp" ) ; this.getContentPane ( ) . setLayout ( null ) ; this.setBounds ( 100 , 100 , 180 , 140 ) ; this.add ( makeButton ( ) ) ; this.setVisible ( true ) ; this.setDefaultCloseOperation ( EXIT_ON_CLOSE ) ; } private JButton makeButton () { b.setText ( "Нажми на меня!" ) ; b.setBounds ( 40 , 40 , 100 , 30 ); b.addActionListener ( new ActionListener ( ) { public void actionPerformed ( ActionEvent e ) { JOptionPane.showMessageDialog ( b , " Привет , мир !" ) ; } }) ; return b ; } public static void main ( String [] args ) throws InvocationTargetException , InterruptedException { // Вызовы Swing должны выполняться потоком диспетчеризации событий. SwingUtilities . invokeAndWait (() -> new Sample ()); } }
Макет устанавливается в null с помощью Container.setLayout(LayoutManager)
метода, поскольку JFrame использует java.awt.BorderLayout в качестве своего менеджера макетов по умолчанию. С BorderLayout все, что добавляется в контейнер, помещается в центр и растягивается для размещения любых других виджетов. Конечно, большинство реальных приложений GUI предпочли бы использовать менеджер макетов вместо размещения всего в абсолютных координатах. [18]
Классы Java Foundation теперь являются ядром платформы Java 2 и включают: набор компонентов графического интерфейса Project Swing, Drag & Drop, Java 2D API, который предоставляет новые возможности 2D и AWT графики, а также поддержку печати, интерфейс Java Look and Feel, новый API Accessibility
Трудно дать практическое правило, где SWT превзойдет Swing или наоборот. В некоторых средах (например, Windows) SWT является победителем. В других (Linux,
VMware,
размещающий Windows) Swing и его оптимизация перерисовки значительно превосходят SWT. Различия в производительности существенны: коэффициенты 2 и более распространены в любом направлении.