Создание графического интерфейса в java. Краткий обзор GUI-фреймворков для Java и мое первое простенькое GUI-приложение на Swing. Прозрачная панель JOptionPane

В Java есть 2 основных пакета для создания графических интерфейсов (Graphics User Interface). Это Abstract Windows Toolkit (AWT) и Swing. AWT использует виджеты операционной системы, поэтому эта библиотека немного быстрее. Но на мой взгляд, Swing более хорошо спроектирован.

В данном туториале мы рассмотрим основные элементы библиотеки Swing и создадим простой интерфейс (GUI) в качестве примера.

Для группировки компонент интерфейса используются контейнеры (Container). Для создания основного контейнера для приложения чаще всего используется контейнер JFrame (есть еще JWindows и JApplet). Проще всего унаследоваться от JFrame тем самым получить доступ ко множеству методов, например:

setBounds(x, y, w, h) - указывает координаты верхней левой вершины окна, а также его ширину и высоту.

setResizable(bool) - указывает, можно ли изменять размер окна.

setTitle(str) - устанавливает название окна.

setVisible(bool) - собственно отображает окно.

setDefaultCloseOperation(operation) - указывает операцию, которая будет произведена при закрытии окна.

Основные элементы управления:

  • JLabel - элемент для отображения фиксированного текста;
  • JTextField - простой edit-box;
  • JButton - обычная кнопка (button);
  • JCheckBox - элемент выбора (аналог checkbox);
  • JRadioButton - радио кнопка

Как видите, все довольно просто и логично.

При отображении элементов управления используются специальные менеджеры - LayoutManager. У всех LayoutManager"ов есть методы для добавления у удаления элементов.

FlowLayout - используется для последовательного отображения элементов. Если элемент не помещается в конкретную строку, он отображается в следующей.

GridLayout - отображения элементов в виде таблицы с одинаковыми размерами ячеек.

BorderLayout - используется при отображении не более 5 элементов. Эти элементы располагаются по краям фрейма и в ценрте: North, South, East, West, Center.

BoxLayout - отображает элементы в виде рядка или колонки.

GridBagLayout - позволяет назначать месторасположение и размер каждого виджета. Это самый сложный, но и самый эффективный вид отображения.

Стоит еще обратить внимание на обработку событий. Для этого используются так называемые Event Listeners.

Ну все, довольно теории, перейдем к примеру GUI:

Import java.awt.*; import java.awt.event.*; import javax.swing.*; public class SimpleGUI extends JFrame { private JButton button = new JButton("Press"); private JTextField input = new JTextField("", 5); private JLabel label = new JLabel("Input:"); private JRadioButton radio1 = new JRadioButton("Select this"); private JRadioButton radio2 = new JRadioButton("Select that"); private JCheckBox check = new JCheckBox("Check", false); public SimpleGUI() { super("Simple Example"); this.setBounds(100,100,250,100); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container container = this.getContentPane(); container.setLayout(new GridLayout(3,2,2,2)); container.add(label); container.add(input); ButtonGroup group = new ButtonGroup(); group.add(radio1); group.add(radio2); container.add(radio1); radio1.setSelected(true); container.add(radio2); container.add(check); button.addActionListener(new ButtonEventListener()); container.add(button); } class ButtonEventListener implements ActionListener { public void actionPerformed(ActionEvent e) { String message = ""; message += "Button was pressed\n"; message += "Text is " + input.getText() + "\n"; message += (radio1.isSelected()?"Radio #1":"Radio #2") + " is selected\n"; message += "CheckBox is " + ((check.isSelected()) ?"checked":"unchecked"); JOptionPane.showMessageDialog(null, message, "Output", JOptionPane.PLAIN_MESSAGE); } } public static void main(String args) { SimpleGUI app = new SimpleGUI(); app.setVisible(true); } }

Примечания:

getContentPane возвращает контейнер верхнего уровня. ButtonGroup служит для создания группы взаимосвязанных радио-кнопок.

Внутренний класс ButtonActionListener реализует интерфейс ActionListener. Для этого необходимо предоставить имплементацию метода actionPerformed.

JOptionPane служит для отображения диалоговых окон.

Жду ваших вопросов и комментариев. Если вы хотите больше узнать о Swing, скажите об этом, и в скором времени я напишу еще одну статью с более сложными приемами и компонентами.

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

И так, какие инструменты нам необходимы:

  • Java Virtual Machine (OpenJDK или Oracle JDK)
  • Intellij IDEA (или другое IDE для Java)

После установки необходимого софта, открываем Intellij IDEA и создаем новый проект: File -> New Project…

Я назвал проект guiBase . Как видно на скрине, папка src не содержит ничего, поэтому создаем в ней наш главный класс, содержащий функцию main .

Public class Main { public static void main(String args) { System.out.println("Hello, Govzalla!"); } }

Содеражние главного класса видите выше. Мы уже сейчас можем создать проект (Build project ) и запустить его (Run ). Внизу в терминале вашего IDE вы увидите сообщение “Hello, Govzalla!“ . Но как вы сами поняли - GUI он не поддерживает.

На данном этапе у нас уже есть работающая программа, но без поддержки GUI. А сейчас в той же папке src создадим GUI Form : New -> GUI Form

Открываем созданную GUI форму, нажимаем на JPanel и задаем его идентификатор в поле field name , я задал panel .

После чего перетаскиваем на форму с правой стороны JTextField , JPasswordField и JButton :

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

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

В данный момент мы имеем форму MainWindow и класс MainWindow расширенный с помощью JFrame . Сейчас нам необходимо определить все добавленные GUI элементы как содержание класса MainWindow this.getContentPane().add(panel); После чего содержание файла MainWindow.java будет изменено следующим образом:

Import javax.swing.*; public class MainWindow extends JFrame { private JTextField textField1; private JPasswordField passwordField1; private JButton button1; private JPanel panel; public MainWindow() { this.getContentPane().add(panel); } }

Если попробуете запустить код, вы снова увидите то же самое сообщение “Hello, Govzalla!“. Дело в том, что мы создали класс и форму к нему, но не создали инстанцию этого класса.

Пришло время изменить файл Main.java и добавить туда код создания нашего GUI:

Import java.awt.*; public class Main { public static void main(String args) { // Создаем инстанцию класса MainWindow MainWindow mainWindow = new MainWindow(); // Упаковываем все элементы с нашей формы mainWindow.pack(); // Изменяем размеры окна mainWindow.setSize(new Dimension(200, 200)); // Отображаем созданное окно mainWindow.setVisible(true); } }

Запускаем код

Нажав на кнопку Button вы заметите, что программа никак не реагирует. Дело в том, что мы еще не добавили слушатель (Listener ) для событий (Events ) кнопки Button.

Слушатель событий (Event listener ) JButton должен быть имплентацией адаптера ActionListener , поэтому добавим следующий код в тело класса MainWindow :

Private class MyButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent actionEvent) { } }

Метод actionPerformed () будет обрабатывать все события кнопки button1, но для начала еще необходимо указать кнопке button1 какой класс будет обрабатывать, поэтому добавим следующий код в конструктор класса MainWIndow: this.button1.addActionListener(new MyButtonListener()); Чтобы наш обработчик не был бессмысленным добавим следующий код в метод actionPerformed ():

@Override public void actionPerformed(ActionEvent actionEvent) { if (textField1.getText().equals(passwordField1.getText())) { JOptionPane.showMessageDialog(null, "Success"); } else { JOptionPane.showMessageDialog(null, "Failure"); } }

Сейчас уже программа будет правильно реагировать на события, не на все события, конечно. Например, если попытаться отключить программу нажав на крестик, окно исчезнет, но программа все еще будет работать, т.к. не добавлен обработчик событий главного окна.

Так исторически сложилось, что с 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 создаются окна и вы убедитесь, что это простая задача. Вот наш код (обсуждать его мы начнем на следующем занятии, т.к. в нем много-много особенностей, знать которые действительно нужно):

import java.awt.*;

import javax.swing.*;

public class MoneyForNothing extends JFrame {

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

public MoneyForNothing () {

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

setSize (new Dimension (600, 400));

setDefaultCloseOperation (EXIT_ON_CLOSE);

setVisible (true);

public static void main (String args) {

MoneyForNothing mfn = new MoneyForNothing ();

А вот этот же код в окне редактирования FAR-а:

Кстати, рекомендуем сразу набирать исходные коды программ в кодировке CP1251 (или в просторечии, в кодировке Windows): переключение кодировок осуществляется клавишей F8, а текущая кодировка высвечивается в строке состояния над областью редактирования.

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


Поздравляем – всего в несколько строк вы создали настоящее графическое окно! Его можно перетаскивать, изменять размеры, сворачивать, разворачивать и закрывать. Правда, окно у нас получилось какое-то блеклое, прямо сказать - «страшненькое». Кроме того, окно выводится в левом верхнем углу экрана, а хотелось бы в центре – там им удобнее пользоваться, да и выглядит такой вывод приятнее. Так что давайте займемся небольшой «полировкой».

Сначала решим вторую задачу – центровка окна. Тут мы рекомендуем остановиться и подумать – как бы вы это сделали?

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

Все, что нужно для размещения окна по центру, это знать размеры самого окна (они, кстати, заданы в конструкторе и составляют прямоугольник 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);

непосредственно за строкой setSize (new Dimension (600, 400)); в конструкторе. Внесите необходимые изменения в исходный код, откомпилируйте программу и запустите на исполнение; окно должно появиться в центре экрана монитора.

Теперь несколько слов о внешнем виде окна. Его странный вид объясняется тем, что разработчики Java стремились добиться того, чтобы вне зависимости от аппаратной платформы и программной «начинки», все графические элементы (окна, кнопки, списки и проч.) имели единую отрисовку и единую цветовую гамму. Для этого они разработали специальный стиль, который назвали «METAL». Если разработчик не предпримет специальных усилий, то элементы графического интерфейса в его программах будут выглядеть именно в этом стиле, без учета особенностей конкретных компьютеров и их программного обеспечения. В отдельных случаях в этом есть смысл, но все-таки, согласитесь, что гораздо лучше, если программа, запущенная на Windows будет похожа на windows-программу, а запущенная на LINUX будет похожа на linux-программу. Добиться этого легко. Все, что нужно - включить в точку входа, перед созданием экземпляра класса следующий код:

try {UIManager.setLookAndFeel

(UIManager.getSystemLookAndFeelClassName ());

catch (Exception lfe) {}

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


В зависимости от настройки свойств экрана вашего монитора отображение окна будет отличаться; мы используем классическую тему Windows XP. У вас это же окно может выглядеть, например, так:

Убедитесь, что все работает как ожидалось: окно выводится в центре экрана и его внешний вид соответствует ожидаемому.

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

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

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

(подсказка: ищите информацию по ключевым словам javax и JFrame). Так что, засучите рукава и удачи!

Замечание

Может случиться, что сформированное окно будет полностью или частично невидимо (из-за того, что вы неправильно рассчитали координаты его вывода на экран). Кнопки управления окна могут также оказаться недоступными. Как же прервать работу приложения не снимая задачу в «Диспетчере задач» или не перезагружая компьютер?

Поскольку мы запускаем программы на исполнение из FAR-а, то прерывание исполнения программы на Java достигается нажатием комбинации клавиш Control-C (здесь «C» - латинская буква, не путайте ее со сходной по начертанию буквой кириллической).

Loading...Loading...