31.07.2023

Графические библиотеки java. Процесс разработки простой GUI программы на языке Java. Swing контейнеры высшего уровня


Предуведомление

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

Этого, увы, не избежать, т.к. рано или поздно мы должны будем прийти к такой точке, после которой подход «на пальцах» становится уже несостоятельным. Сейчас такой момент наступает. Так что давайте соберемся с духом, засучим рукава и приступим.

На предыдущем занятии () мы сформировали и вывели на экран монитора графическое окно и попутно решили некоторые задачи, касающиеся его внешнего вида и расположения. Теперь мы обсудим то, что осталось «за кадром».

Вы, вероятно, обратили внимание на то, что в начале исходного кода есть две следующие строчки:

import java.awt.*;

import javax.swing.*;

Здесь надо немного задержаться. Вспомним, что ранее мы упоминали о том, что среда программирования Java включает в себя множество библиотек, предназначенных для поддержки сети, графики, работы с базами данных, обмена сообщениями и т.д. Именно библиотеки доставляют Java всю мощь и универсальность.

В Java вместо термина «библиотека» используется понятие «пакет». Указанные выше строки как раз и подключают необходимые пакеты для формирования графического интерфейса. Позже вы увидите, что мы будем использовать и другие пакеты, но сейчас нам достаточно указанных двух.

Пакеты включают в себя необходимые классы и интерфейсы (об интерфейсах мы расскажем в свое время), обеспечивающие ту или иную функциональность будущего приложения. Наличие звездочки («*») указывает на то, что программист импортирует все содержимое пакета, без точного указания входящих в него классов или интерфейсов. Может показаться, что в случае больших пакетов, итоговый объектный код может оказаться чересчур большим, но беспокоиться не стоит: компилятор Java достаточно «умен», чтобы использовать только то, что действительно необходимо вашей программе; все, что программе не нужно, компилятор включать в объектный код попросту не станет. Если хотите, вы можете использовать несколько иную форму подключения пакетов, например,

import java.awt.Window;

import javax.swing.JFrame;

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

Импортирование (подключение) пакета к разрабатываемой программе производится ключевым словом import, после которого идет имя пакета. Каждый пакет должен импортироваться отдельно (т.е. нельзя написать import java.awt.*, javax.swing.*;). Конечно, объем исходного кода при этом несколько увеличивается, но очень незначительно. Все классы и интерфейсы, составляющие вашу программу, должны располагаться строго после конструкций import, иначе компилятор сгенерирует сообщение об ошибках компиляции.

Первый пакет (начинающийся с java.awt) обеспечивает прежде всего взаимодействие программ на Java с графической подсистемой операционной системы. Вспомните, что Java является кроссплатформенным языком программирования и генерирует единый объектный код вне зависимости от операционной системы, на которой этот код будет выполняться. Поэтому Java «вынуждена» обращаться к ресурсам, предоставляемым той операционной системой, которая установлена на компьютере пользователя. Один из таких ресурсов - графика (кроме графики Java обращается к «услугам» операционной системы для доступа к файловой системе и другим ресурсам). Так вот, пакет java.awt.* позволяет графическим интерфейсам, написанным на Java задействовать графические возможности операционной системы и отображаться графическим объектам, созданным в программах Java, на экране монитора. Здесь мы немного задержимся.

Все графические компоненты в Java подразделяются на две категории: легковесные (lightweight) и тяжеловесные (heavyweight). Подавляющее большинство графических компонентов (кнопки, списки, деревья, метки, таблицы и т.д.) являются легковесными. Это означает, что операционная система абсолютно ничего о них не знает и даже не «подозревает» об их существовании. Легковесные компоненты принадлежат окнам (подобных тому, что мы выводили на предыдущем занятии) и отображаются в этих окнах.

Если мы хотим отобразить в окне кнопку, то нам достаточно определить ее кодом, подобным следующему

JButton buttonPressMe = new JButton («Нажми меня»);

и разместить ее в указанном месте окна (соответствующие детали будут описаны позже). Кнопка – легковесный объект и операционная система не имеет о кнопке никаких сведений (для операционной системы кнопка вообще не существует). О кнопке «знает» только окно, в котором она размещена. Окно отрисовывает кнопку, перехватывает события, происходящие с кнопкой, перерисовывает кнопку если она была чем-либо заслонена и т.д. А вот само окно как таковое – о нем операционная система осведомлена и именно потому, что окно – тяжеловесный компонент. Только окно имеет доступ к ресурсам операционной системы (в частности – графическим).

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

Dimension sSize = Toolkit.getDefaultToolkit ().getScreenSize ()

Что может предоставить такую информацию? Операционная система и только она! Далее, мы использовали код

try {UIManager.setLookAndFeel

(UIManager.getSystemLookAndFeelClassName ());

catch (Exception lfe) {}

для того, чтобы внешний вид окна соответствовал стандарту, принятому в конкретной операционной системе. Что может предоставить такую информацию? Опять же – операционная система! Так что для создания графических интерфейсов без пакета java.awt.* нам не обойтись.

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

Второй импортируемый пакет (начинающийся с javax.swing) отвечает за формирование легковесных графических интерфейсов (есть и другие пакеты, но этот – самый важный и практически всегда используемый). Изучать и осваивать этот пакет мы будем постепенно, т.к. он весьма большой и достаточно сложный. Этим мы начнем заниматься на следующем занятии, а пока обратимся к следующей строке исходного кода:

public class MoneyForNothing extends JFrame {

Здесь новыми являются два элемента: ключевое слово extends и слово JFrame.

Ключевое слово extends (в переводе означает «расширить», но по смыслу близко к слову «наследует» или к словосочетанию «заимствовать свойства и поведение») выражает фундаментальную концепцию объектно-ориентированного программирования (или проще говоря, программирования, основанного на классах). Эта концепция носит название «наследование». С этим надо хорошенько разобраться.

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

Конечно, громадный дизель для танкера не сравнить с крошечным спиртовым двигателем для авиамодели, но они (если так можно выразиться) – пусть и дальние, но родственники. У них общий предок – некий абстрактный двигатель, а сами двигатели – его потомки (пусть даже очень и очень дальние).

В программировании такой предок обычно называется «родитель» или «суперкласс», т.е. класс, от которого произошли другие классы. Имя суперкласса указывается непосредственно после extends. Таким образом, в переводе на обычный язык, вышеприведенный фрагмент кода можно прочитать так: «класс... расширяет класс JFrame», «класс... наследует класс JFrame» или «класс... заимствует свойства и поведение класса JFrame». В классе JFrame определены основные свойства и поведение «стандартных» графических окон. Сам класс JFrame находится в пакете javax.swing.* и именно его мы и импортировали в начале программы.

JFrame – это родитель (в терминологии Java – суперкласс) графических окон (есть еще и другие окна, например, диалоговые, но о них мы поговорим в свое время). Если обратиться к документации по Java , то в ней вы обнаружите, что в классе JFrame имеются несколько конструкторов, полей и около двух десятков методов, которые определяют поведение некоего «стандартного» окна. Таким образом, наш класс с именем MoneyForNothing является наследником класса JFrame (обычно говорят не о наследниках, а о потомках или о дочерних классах).

Обратите внимание, что класс JFrame сам в свою очередь является наследником нескольких классов (большая часть которых принадлежит уже знакомому нам пакету java.awt.*):

Чтобы уже не возвращаться к этому вопросу, обращаем ваше внимание на то, что в вершине иерархии наследования Java лежат классы из пакета java.lang.*. Это единственный пакет из JDK, который не нужно явно импортировать – он всегда импортируется автоматически. Судя по этой «лесенке», класс JFrame является пра-пра-правнуком java.lang.Object (картинка, приведенная выше по-научному называется иерархией классов).

Все компоненты графического пользовательского интерфейса (сокращенно GUI, от Graphical User Interface), которые, напомним, являются легковесными элементами, должны быть размещены внутри основного окна – наследника JFrame. Сейчас у нас никаких компонентов нет, но скоро они появятся – обещаем.

А теперь «пробежимся» напоследок по нашему исходному коду, который выглядит так:

// Конструктор

public MoneyForNothing () {

setTitle ("Добро пожаловать в Money for Nothing");

setSize (new Dimension (600, 400));

Dimension sSize = Toolkit.getDefaultToolkit ().getScreenSize (),

fSize = getSize ();

if (fSize.height > sSize.height) {fSize.height = sSize.height;}

if (fSize.width > sSize.width) {fSize.width = sSize.width;}

setLocation ((sSize.width - fSize.width)/2,

(sSize.height - fSize.height)/2);

setDefaultCloseOperation (EXIT_ON_CLOSE);

setVisible (true);

Прежде всего, мы задаем заголовок окна (метод setTitle («...»)). Затем задаются размеры окна по горизонтали и вертикали (метод setSize (...)). После определения разрешения экрана монитора расчитываются координаты верхнего левого угла нашего окна и окно выводится (метод setLocation (...)) в указанном месте экрана.

После этого мы определяем что нужно делать при закрытии окна в системном меню; в данном случае видно, что приложение должно завершить свою работу (EXIT_ON_CLOSE). За этой короткой и простой строчкой на самом деле скрывается удивительно интересный и интригующий мир обработки событий. Скажем сразу: понимание механизма обработки событий в Java – ключевой момент в разработке графических приложений и начиная со следующего занятия мы займемся как раз именно этим.

Наконец, последняя строка (метод setVisible (true)) делает окно видимым.

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

На этом наше занятие подходит к концу. Самое важное, что вы должны извлечь из него – концепция наследования (заимствования). Это, действительно, основополагающая концепция. Без нее в Java нельзя создать сколько нибудь сложную и полезную программу, так что не торопитесь двигаться дальше, а еще раз внимательно просмотрите и обдумайте все, что мы к этому моменту изучили.

Удачи и до скорой встречи!

Так исторически сложилось, что с UI мне приходилось работать очень мало. Видимо, поэтому мне так интересные всякие там Qt и wxWidgets — все кажется новым, интересным, необычным. Впрочем, коль скоро я взялся за изучение Java , речь сегодня пойдет не о Qt и не о wxWidgets, а о Swing. Сегодня совместными усилиями мы напишем простенькое GUI-приложение на Java, с кнопочками, списками и даже умеющее менять шкурки!

Ситуация с GUI фреймворками в мире Java несколько запутанная. Насколько я смог разобраться, дела обстоят следующим образом.

  • AWT (Abstract Window Toolkit) был первым GUI фреймворком. Идея была правильная — AWT использует нативные контролы, то есть, они выглядят и физически являются родными, независимо от того, где вы запускаете свое приложение. К сожалению, оказалось, что (1) общих для различных окружений контролов мало и (2) писать кроссплатформенные нативные интерфейсы так, чтобы ничего не поползло и не разъехалось, очень сложно;
  • Поэтому на смену AWT пришел Swing . Swing использует формочки, создаваемые AWT, на которых он своими силами рисует контролы. Работает это хозяйство, понятно дело, медленнее, но зато UI становится намного более портабельным. Swing предлагает на выбор программисту множество Look&Feel, благодаря которым можно сделать либо так, чтобы приложение выглядело и вело себя одинаково как под Windows, так и под Linux, либо чтобы приложение было очень похоже на нативное независимо от того, где его запускают. В первом случае приложение проще отлаживать, во втором — становятся счастливее пользователи. Кстати, изначально Swing был сделан парнями из Netscape;
  • SWT (Standard Widget Toolkit) — фреймворк, написанный в IBM и используемый в Eclipse. Как и в AWT, используются нативные контролы. SWT не входит в JDK и использует JNI, поэтому не очень соответствует идеологии Java «написано однажды, работает везде». Вроде как при очень сильном желании можно запаковать в пакет реализацию SWT для всех-всех-всех платформ, и тогда приложение вроде как даже станет портабельным, но только до тех пор, пока не появится какая-нибудь новая операционная система или архитектура процессора;
  • JavaFX активно пилится в Oracle и позиционируется, как скорая замена Swing. Идеологически JavaFX похож на Swing, то есть, контролы не нативные. Среди интересных особенностей JavaFX следует отметить хардверное ускорение, создание GUI при помощи CSS и XML (FXML), возможность использовать контролы JavaFX’а в Swing’е, а также кучу новых красивых контролов, в том числе для рисования диаграмм и 3D. Видео с более детальным обзором JavaFX можно . Начиная с Java 7, JavaFX является частью JRE/JDK ;
  • NetBeans Platform (не путать с NetBeans IDE!) — это такая штука, которая, как я понял, работает поверх Swing и JavaFX, предоставляет как бы более удобный интерфейс для работы с ними, а также всякие дополнительные контролы. В одном приложении, использующем NetBeans Platform, я видел возможность перетаскивать вкладки drug&drop’ом, располагая панели в окне подобно тому, как это делают тайловые оконные менеджеры . По всей видимости, сам Swing так не умеет. Почитать про NetBeans Platform поподробнее ;

Не исключено, что есть и другие фреймворки. Наиболее каноничным на сегодняшний день является Swing, поэтому им и займемся.

Выше что-то говорилось про какие-то там Look&Feel. Чтобы лучше понять, о чем идет речь, давайте напишем программу, которая выводит список этих самых Look&Feel и позволит переключаться между ними прямо в процессе работы программы.

Наше приложение будет выглядеть следующим образом под Ubuntu:

А так оно будет выглядеть при запуске под Windows:

Как видите, JRE под Windows и Linux включают в себя разный набор L&F. Кроме того, вы можете подключить сторонний Look&Feel или даже написать свой. По умолчанию используется L&F Metal, который во всех ОС и оконных менеджерах выглядит более-менее одинаково. Если вам больше нравятся круглые кнопочки, то вместо Metal можно использовать Look&Feel Nimbus. Если вам хочется, чтобы приложение было похоже на нативное, то под Linux следует выбрать L&F GTK+ (интересно, а если пользователь сидит под KDE?), а под Windows — L&F Windows. Неплохой идеей, видимо, будет предусмотреть в вашей программе возможность переключаться между различными L&F. С другой стороны, при этом придется тестировать работу приложения со всеми этими L&F.

Давайте посмотрим на исходный код приложения. Коллеги UI-щики заверили меня, что никаких WYSIWYG редакторов они не используют, а если используют, то разве что для быстрого прототипирования. Из неплохих WYSIWYG редакторов назывался JFormDesigner . Говорят, генерируемый им код даже похож на код, написанный человеком, а не адовую().последовательность().вызовов().методов(). В общем, весь код писался лапками в IntelliJ IDEA .

public static void main(String args) {

@Override
public void run() {
createGUI() ;
}
} ) ;
}

В Swing и AWT, если мы хотим что-то поменять в UI, мы должны делать это из event dispatching thread. Статический метод invokeLater принимает класс, реализующий интерфейс Runnable, и вызывает его метод run() внутри event dispatching thread. Если вам не знаком приведенный выше синтаксис, то это такой способ в Java объявить класс, не присваивая ему имени. Классы без имени называются анонимными. Часто анонимные классы в Java выполняют ту же роль, что играют лямда-фукнции в функциональных языках программирования. Помимо прочего, поддерживаются и замыкания. Интересно, что, в отличие от лямбд, анонимные классы в Java позволяют передать сразу пачку методов. Притом, при помощи наследования и абстрактных классов, для всех или части методов можно взять их реализацию по умолчанию.

Аннотация @Override проверяет, что метод run() действительно переопределит метод интерфейса Runnable. Без нее при переопределении метода мы можем случайно сделать опечатку и определить новый метод вместо того, чтобы переопределить существующий. Впрочем, в данном конкретном случае аннотация, видимо, не очень полезна, и, наверное, даже является лишней.

В итоге event dispatching thread вызовет метод createGUI(), полный код которого следующий:

private static void createGUI() {
JList< String> list = new JList<> () ;
list.setSelectionMode (ListSelectionModel .SINGLE_SELECTION ) ;

JScrollPane listScrollPane = new JScrollPane (list) ;

JPanel topPanel = new JPanel () ;
topPanel.setLayout (new BorderLayout () ) ;
topPanel.add (listScrollPane, BorderLayout .CENTER ) ;

ActionListener updateButtonListener = new UpdateListAction(list) ;
updateButtonListener.actionPerformed (
new ActionEvent (list, ActionEvent .ACTION_PERFORMED , null )
) ;

JButton updateListButton = new JButton ("Update list" ) ;
JButton updateLookAndFeelButton = new JButton ("Update Look&Feel" ) ;

JPanel btnPannel = new JPanel () ;
btnPannel.setLayout (new BoxLayout (btnPannel, BoxLayout .LINE_AXIS ) ) ;
btnPannel.add (updateListButton) ;
btnPannel.add (Box .createHorizontalStrut (5 ) ) ;
btnPannel.add (updateLookAndFeelButton) ;

JPanel bottomPanel = new JPanel () ;
bottomPanel.add (btnPannel) ;

JPanel panel = new JPanel () ;
panel.setBorder (BorderFactory .createEmptyBorder (5 ,5 ,5 ,5 ) ) ;
panel.setLayout (new BorderLayout () ) ;
panel.add (topPanel, BorderLayout .CENTER ) ;
panel.add (bottomPanel, BorderLayout .SOUTH ) ;

JFrame frame = new JFrame ("Look&Feel Switcher" ) ;
frame.setMinimumSize (new Dimension (300 , 200 ) ) ;
frame.setDefaultCloseOperation (WindowConstants .EXIT_ON_CLOSE ) ;
frame.add (panel) ;
frame.pack () ;
frame.setVisible (true ) ;

UpdateListButton.addActionListener (updateButtonListener) ;
updateLookAndFeelButton.addActionListener (
new UpdateLookAndFeelAction(frame, list)
) ;
}

Тут, в общем-то, нет ничего супер сложного. Создаются кнопки, список, список заворачивается в JScrollPane, чтобы у списка была прокрутка. Элементы управления располагаются во фрейме при помощи панелей. Панели могут иметь различные лайоуты, здесь мы использовали BorderLayout и BoxLayout . Принцип аналогичен тому, что используется в wxWidgets .

Для реакции на различные события, например, нажатия кнопок, используются классы, реализующие интерфейс ActionListener. В приведенном выше коде используется два таких класса — UpdateListAction и UpdateLookAndFeelAction. Как нетрудно догадаться по названию, первый класс отвечает за обработку нажатий на левую кнопку «Update list», второй — на правую кнопку «Update Look&Feel». ActionListener’ы привязываются к кнопкам при помощи метода addActionListener. Поскольку сразу после запуска приложения нам хочется увидеть список доступных Look&Feel, мы эмулируем нажатие на кнопку «Update list». Для этого мы создаем экземпляр класса ActionEvent и передаем его в качестве аргумента методу actionPerformed класса UpdateListAction.

Реализация класса UpdateListAction следующая:

static class UpdateListAction implements ActionListener {
private JList< String> list;

public UpdateListAction(JList< String> list) {
this .list = list;
}

@Override
public void actionPerformed(ActionEvent event) {
ArrayList< String> lookAndFeelList = new ArrayList<> () ;
UIManager.LookAndFeelInfo infoArray =

int lookAndFeelIndex = 0 ;
int currentLookAndFeelIndex = 0 ;
String currentLookAndFeelClassName =
UIManager .getLookAndFeel () .getClass () .getName () ;

for (UIManager.LookAndFeelInfo info : infoArray) {
if (info.getClassName () .equals (currentLookAndFeelClassName) ) {
currentLookAndFeelIndex = lookAndFeelIndex;
}
lookAndFeelList.add (info.getName () ) ;
lookAndFeelIndex++;
}

String listDataArray = new String [ lookAndFeelList.size () ] ;
final String newListData =
lookAndFeelList.toArray (listDataArray) ;
final int newSelectedIndex = currentLookAndFeelIndex;

SwingUtilities .invokeLater (new Runnable () {
@Override
public void run() {
list.setListData (newListData) ;
list.setSelectedIndex (newSelectedIndex) ;
}
} ) ;
}
}

В конструкторе передается указатель на список, в котором мы будет отображать доступные Look&Feel. На самом деле, поскольку UpdateListAction является вложенным классом нашего основного класса LookAndFeelSwitcher, у него есть возможность обращаться напрямую к полям создавшего его экземпляра LookAndFeelSwitcher. Но функциональщик внутри меня сопротивляется такому подходу, поэтому я решил передать ссылку на список явно через конструктор.

Метод actionPerformed будет вызываться при нажатии на кнопку. Код этого метода довольно тривиален — мы просто используем статические методы класса UIManager для получения списка доступных Look&Feel, а также определения текущего Look&Feel. Затем обновляется содержимое списка и выбранный в нем элемент. Тут нужно обратить внимание на два момента. Во-первых, каждый Look&Feel имеет имя и имя класса , это разные вещи. Пользователю мы должны показывать имена, а при переключении Look&Feel использовать имя класса. Во-вторых, обратите внимание на то, как создаются final переменные newListData и newSelectedIndex, которые затем используются в анонимном классе. Это и есть тот самый аналог замыканий, речь о котором шла ранее. Очевидно, использование не final переменных в замыканиях привело бы к печальным последствиям.

Наконец, рассмотрим класс UpdateLookAndFeelAction:

static class UpdateLookAndFeelAction implements ActionListener {
private JList< String> list;
private JFrame rootFrame;

public UpdateLookAndFeelAction(JFrame frame, JList< String> list) {
this .rootFrame = frame;
this .list = list;
}

@Override
public void actionPerformed(ActionEvent e) {
String lookAndFeelName = list.getSelectedValue () ;
UIManager.LookAndFeelInfo infoArray =
UIManager .getInstalledLookAndFeels () ;

for (UIManager.LookAndFeelInfo info : infoArray) {
if (info.getName () .equals (lookAndFeelName) ) {
String message = "Look&feel was changed to " + lookAndFeelName;
try {
UIManager .setLookAndFeel (info.getClassName () ) ;
SwingUtilities .updateComponentTreeUI (rootFrame) ;
} catch (ClassNotFoundException e1) {
message = "Error: " + info.getClassName () + " not found" ;
} catch (InstantiationException e1) {
message = "Error: instantiation exception" ;
} catch (IllegalAccessException e1) {
message = "Error: illegal access" ;
} catch (UnsupportedLookAndFeelException e1) {
message = "Error: unsupported look and feel" ;
}
JOptionPane .showMessageDialog (null , message) ;
break ;
}
}
}
}

Здесь мы просто (1) находим L&F с именем, равным имени, выбранному в списке, (2) меняем L&F при помощи static метода setLookAndFeel класса UIManager и (3) перерисовываем главный фрейм нашего UI, а также, рекурсивно, расположенные на нем элементы, при помощи static метода updateComponentTreeUI класса SwingUtilities. Наконец, мы уведомляем пользователя при помощи сообщения, все ли прошло успешно.

Также хотелось бы сказать пару слов об отладке GUI-приложений на Java, и не только GUI. Во-первых, в Swing есть такое волшебное сочетание клавиш Ctr + Shift + F1, которое выводит в stdout информацию о том, как расположены контролы. Очень полезно, если хочется слизать UI у конкурентов. Во-вторых, есть такой интересный хоткей Ctr + \. Если нажать его в консоли работающего приложения на Java, будут выведены все нитки и их стектрейсы. Удобно, если вы словили дэдлок. Наконец, в-третьих, во время разработки GUI бывает полезно разукрасить панели в разные цвета. Сделать это можно так:

buttonsPanel.setBackground (Color .BLUE ) ;

Итак, логика Game of Life реализована. Хотелось бы насладиться процессом созерцания многообразия форм «Жизни» на экране своего монитора. Что для этого понадобится?

Само окно с меню и кнопками, а также его поведение будут создаваться с помощью библиотеки Swing. Прорисовка же процесса эволюции нашей «Жизни» — посредством библиотеки AWT (точнее, Java 2D). Это два основных пакета для создания графических интерфейсов на Java.

Работа AWT изначально основана на так называемых peer-интерфейсах. Суть состоит в том, что при необходимости вывода на экран объекта Java, операционной системой создается парный ему графический объект, который, собственно, и отображается. Эти два объекта взаимодействуют между собой во время работы программы. Такая реализация приводит к тому, что для каждой платформы приходится выпускать собственный JDK.

Позднее в AWT были созданы компоненты, не использующие peer-интерфейсы — «легкие» (lightweight) компоненты. Библиотека этих компонентов была названа Swing. То есть Swing, по сути, является расширением AWT.

Сама же AWT была дополнена новыми средствами рисования и вывода изображений, получившими название Java 2D.

Перечислю с коротким описанием основные элементы Swing.

Базовым строительным блоком всей библиотеки визуальных компонентов Swing является JComponent . Это суперкласс каждого компонента. Он является абстрактным классом, поэтому в действительности вы не можете создать JComponent, но он содержит буквально сотни функций, которые каждый компонент Swing может использовать как результат иерархии классов.

JFrame (окно приложения) — основной контейнер, позволяющий добавлять к себе другие компоненты для их организации и предоставления пользователю. JFrame выступает в качестве моста между независимыми от ОС Swing-частями и реальной ОС, на которой они работают. JFrame регистрируется как окно в ОС и таким образом получает многие из знакомых свойств окна операционной системы.

JMenu/JMenuItem/JMenuBar — предназначены для разработки системы меню в JFrame. Основой любой системы меню является JMenuBar, каждый JMenu и JMenuItem создается с ним. JMenu является подклассом JMenuItem. Однако по внешнему виду они имеют отличие: JMenu используется для содержания других JMenuItem и JMenu; JMenuItem при выборе активизирует действие.

JLabel (метка) — предназначен для описания (текстового или графического) других элементов.

JButton (кнопка) — основной активный компонент, позволяющий выполнить какие-либо действия при ее нажатии. Кроме стандартных методов, управляющих отображением компонента, содержит группу методов для управления своим состоянием (активная/неактивная, выбранная/не выбранная, мышка сверху/мышки нет, нажата/отжата).

JTextField (текстовое поле) — позволяет пользователю вводить текстовые данные, которые могут быть обработаны в программе.

JTextArea развивает JTextField, позволяя вводить несколько строк.

JPasswordField (поле для ввода пароля) — разновидность JTextField, позволяющая скрывать вводимые символы.

JComboBox (комбинированный список) — позволяет пользователю выбрать элемент из существующего списка (или добавить к списку новый элемент).

JCheckBox (флажок)и JRadioButton (переключатель) — предоставляют пользователю варианты для выбора. JRadioButton обычно группируются вместе для предоставления пользователю вопроса с принудительным ответом (ответы взаимоисключающие — может быть только один ответ на вопрос). Как только вы выбрали JRadioButton, вы не можете снять его отметку до тех пор, пока не выберете другой вариант из группы. JCheckBox работает иначе. Он позволяет отмечать/снимать отметку с варианта в любое время и выбирать несколько ответов на вопрос. Классом, который позволяет группировать вместе компоненты JCheckBox или JRadioButton, является класс ButtonGroup .

JSlider — элемент для выбора числового значения из графически представленного диапазона.

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

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

JToolTip — это небольшие «пузырьки», которые всплывают, когда вы наводите и держите курсор мышки над чем-нибудь. Они могут быть очень полезны в приложениях, предоставляя подсказки для элементов, детализируя информацию или даже показывая полный текст элемента в сжатых UI. Они активизируются в Swing, если оставить курсор мышки над компонентом на определенное количество времени; обычно они появляются примерно через секунду после остановки мышки и остаются видимыми до тех пор, пока курсор остается над компонентом.

JOptionPane — класс для предоставления UI-разработчикам способа выдачи простых сообщений (об ошибке или другой информации) и быстрого получения данных (например, имени или номера).

JScrollPane — Swing-компонент для обработки всех действий по прокрутке.

JList является полезным компонентом для предоставления пользователю многих вариантов для выбора. Вы можете представлять его как расширение JComboBox. JList предоставляет больше вариантов и добавляет возможность выбора нескольких вариантов. Выбор между JList и JComboBox часто заключается в следующем: если вам требуется возможность множественного выбора или имеется более 15 вариантов (хотя это число не является общим правилом), вы должны всегда выбирать JList. Вы должны использовать JList совместно с JScrollPane, поскольку он может предоставлять больше вариантов, чем помещается в видимой области. JList имеет также модель выбора, которую вы можете установить в различные типы выбора вариантов. Такими типами являются: одиночный выбор (вы можете выбрать только один вариант), одиночный интервал (вы можете выбрать смежные варианты, но в любом их количестве) и множественный интервал (вы можете выбрать любое число вариантов в любых комбинациях).

Давыдов Антон Валериевич
Студент ТГУ, Россия, г. Тольятти
Научный руководитель: Ерофеева Е.А.

Пользовательский интерфейс на Java прошел весьма тернистый путь становления и развития. Его долгое время обвиняли в жадности к ресурсам системы, медленной работе и ограниченной функциональности. Появление.NET с более быстрыми графическими компонентами еще больше пошатнуло позиции Java. Но подобная конкуренция лишь подстёгивала разработчиков Java к развитию и улучшению графических библиотек. И в этой статье мы посмотрим, что из этого получилось.

Abstract Window Toolkit

Abstract Window Toolkit (сокращённо AWT) впервые была выпущена в 1995 году компанией Sun Microsystems. Это была первая попытка создать графический интерфейс для Java. AWT выступал в качестве прослойки, вызывающей методы из библиотек, написанных на С. А эти методы, в свою очередь, использовали графические компоненты операционной системы . С одной стороны, программа, построенная таким образом, внешне была похожа на все остальные программы в используемой операционной системе, но с другой, одна и та же программа может выглядеть совершенно по-разному на разных операционных системах, что осложняло разработку. К тому же, ради мультиплатформенности пришлось унифицировать интерфейсы вызовов компонентов, что привело к несколько урезанной функциональности. Набор компонентов также довольно скромный. Например, отсутствуют таблицы, а в кнопки нельзя поместить иконки. AWT старается автоматически освобождать использованные ресурсы. Это влияет на производительность и усложняет архитектуру. AWT прост для освоения, но написание чего-то сложного вызывает затруднения. Сейчас AWT используется в основном для аплетов. Oracle в данный момент поощряет переход разработчиков на Swing, как более безопасный.

Рис.1 – Образец программы, написанной с использованием AWT в среде Windows

После AWT, в 1998 году, Sun выпустила Swing. Он полностью написан на Java и для отрисовки использует 2D. В Swing гораздо больше разнообразных компонентов, чем в AWT. Сами компоненты стало гораздо проще создавать, наследуя их от существующих . Также была введена возможность использования различных стилей и скинов. Однако, скорость работы ранних версий Swing была довольно низкой, а ошибки в написании программы могли и вовсе привести к зависанию операционной системы.

Однако, благодаря лёгкому освоению и наличию большого количества документации, Swing стал самым популярным графическим интерфейсом в Java. На его основе появилось множество расширения, например SwingX и JGoodies, которые ещё больше упрощают создание визуально сложных приложений. Все современные среды программирования на Java включают в себя графические редакторы Swing. Даже не смотря на то, что сейчас существуют более современные фреймворки, Swing остаётся самым популярным.


Рис.2 – Образец программы, написанной с использованием Swing

Standard Widget Toolkit

SWT был выпущен компанией IBM во времена, когда Swing был ещё медленным, и в основном для продвижения среды программирования Eclipse. Как и AWT, SWT использует компоненты ОС, но для различных платформ используются различные интерфейсы взаимодействия . Таким образом для каждой операционной системы необходимо поставлять отдельную JAR-библиотеку. Это позволяет более полно использовать функции, соответствующие различным операционным системам. А недостающие компоненты были реализованы с помощью 2D. Тем не менее, SWT получилась более сложной для освоения, чем Swing. Кроме того, программист должен сам реализовывать освобождение ресурсов приложением.

Рис.3 – Образец программы, написанной с использованием Swing

JavaFX была выпущена в 2008 году компанией Oracle. Она позиционируется как платформа для создания насыщенного интернет-приложения. Для отрисовки используется графический конвейер, что значительно ускоряет работу приложения. Имеется большой набор встроенных компонентов. Также имеются отдельные компоненты для построения графиков. Реализована поддержка мультимедийного контента, анимации и даже множественное касание. Внешний вид компонентов настраивается при помощи CSS-стилей . Кроме того, в набор утилит JavaFX входит возможность сделать родной инсталлятор для самых популярных платформ: exe или msi для Windows, deb или rpm для Linux, dmg для Mac. На сайте Oracle имеется подробная документация и большое число готовых примеров.

Таким образом, описав основным особенности и недостатки вышеперечисленных графических пользовательских интерфейсов, мы можем решить, для каких задач они лучше подходят. Abstract Window Toolkit больше подойдёт для создания аплетов. Новичку можно порекомендовать Swing в виду того, что для него можно найти огромное количество документации в интернете, в том числе и на русском языке. Для создания насыщенных интернет-приложений отлично подойдёт JavaFX.

Список использованных источников

    Рыженко А. В. Объектно-ориентированное программирование: Учебно-методический комплекс по дисциплине для специальности 010501 – "Прикладная математика и информатика". – 2007.

    Хабибуллин И. Ш. Java 7 (4-е изд.). – БХВ-Петербург, 2012.

    Clarke J., Connors J., Bruno E. J. JavaFX: Developing Rich Internet Applications. – Pearson Education, 2009.

    Northover S., Wilson M. Swt: the standard widget toolkit, volume 1. – Addison Wesley Professional, 2004.


© 2024
zane-host.ru - Программы. Компьютеры. Сетевое оборудование. Оргтехника