Как в java сделать окно с кнопками

Обновлено: 18.05.2024

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

Кнопки JButton

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

Основное время работы с кнопками связано не столько с их созданием и настройкой, сколько с размещением в контейнере и написанием обработчиков событий.

Внешний вид кнопок JButton можно легко изменить, не меняя менеджера внешнего вида и поведения. С интерфейсом кнопок можно делать практически все — сопоставлять каждому действию пользователя своё изображение, убирать рамку, закрашивать в любой цвет, перемещать содержимое по разным углам, не рисовать фокус.

Рассмотрим пример, в котором будут созданы кнопки JButton разных форм и размеров.

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

Первой в контейнер помещается самая обычная кнопка. Затем следует кнопка, на которой вместо текста располагаются иконки на «все случаи жизни». Для определения иконок применяются свойства, перечисленные в таблице.

СвойстваОписание
icon Установка «обычной» иконки.
rolloverlcon Получение эффекта «наведения мыши». Когда указатель мыши оказывается на кнопке, появляется эта иконка. Обычно в этом случае используется та же иконка, только к ней добавляется эффект объема или изменяется цвет части иконки.
pressedlcon Представление иконки, которая отображается при нажатии на кнопке. Иконка остается до тех пор, пока кнопка мыши не отпущена.
disabledlcon Если вы задаете иконку посредством данного свойства, то, когда кнопка будет отключена (метод setEnabled(false)), появится специальная иконка. Если специальной иконки нет, а обычная иконка есть, то в качестве иконки для отключенной кнопки будет использована черно-белая копия обычной иконки.

Если вывести кнопку с иконками на экран «как есть», она будет выглядеть не очень хорошо, поскольку у нее останутся все свойственные обычной кнопке с текстом свойства — будет рисоваться рамка, при наличии фокуса появится контур, а при нажатии она будет закрашиваться темным цветом. Чтобы убрать эти эффекты, в примере и задействуются методы setBorderPainted(), setFocusPainted() и setContentAreaFilled().

Метод setBorderPainted() позволяет отключить прорисовку рамки. То же самое можно сделать вызовом setBorder(null), но в этом случае нельзя вернуть кнопке ее рамку обратно. Метод setFocusPainted() отключает прорисовку специального контура, проявляющегося, если кнопка обладает фокусом ввода. setContentAreaFilled() дает возможность отключить закраску кнопки в нажатом состоянии. С этими методами лучше быть осторожней, потому что пользователю с такой кнопкой работать гораздо сложнее: будет непонятно, выбрана кнопка или нет, где она начинается и т. п. Применять эти методы лучше только в тех приложениях, в которых весь интерфейс основан на разнообразных изображениях (например, в играх).

Методом setBackground() можно устанавливать цвет заполнения JButton. Цвет заполнения изменится только в том случае, если у кнопки включено свойство непрозрачности (opaque). По умолчанию оно установлено.

Кнопки JButton также, как и надписи JLabel, позволяют определять интерфейс с использованием HTML, что вместе с широчайшими возможностями по настройке расположения содержимого и по управлению всеми аспектами внешнего вида кнопок дает неограниченную власть над видом приложения.

Настройки кнопок JButton

В таблице представлены параметры, позволяющие выполнить определенные настройки интерфейса кнопок JButton.

СвойстваОписание
margin Управление размером полей, которые отделяют содержимое кнопки (текст и иконку) от ее границ.
verticalAlignment,
horizontalAlignment
Вертикальное и горизонтальное выравнивание всего содержимого кнопки (и значка, и текста) относительно границ кнопки. С их помощью это содержимое можно поместить в любой угол кнопки или в ее центр (по умолчанию оно там и находится).
horizontalTextPosition,
verticalTextPosition
Управление по горизонтали и вертикали положением текста кнопки относительно ее иконки, если она есть, конечно.
iconTextGap Свойство позволяет изменить расстояние между иконкой и текстом.

СобытиеОписание
ActionEvent
слушатель ActionListener
Событие при нажатии и отпускании кнопки.
ChangeEvent
слушатель ChangeListener
С помощью данного события модель кнопок ButtonModel взаимодействует со своим UI-представителем. Модель при изменении хранящегося в ней состояния кнопки (это может быть смена включенного состояния на выключенное, обычного на нажатое и т. п.) запускает событие ChangeEvent. UI-представитель обрабатывает это событие и соответствующим образом перерисовывает кнопку.
ItemEvent
слушатель ItemListener
Событие о смене состояния возникает в компонентах, которые имеют несколько равноценных состояний (например, флажки и переключатели).

В примере после создания первой кнопки к ней подключаются слушатели событий. Для событий ActionEvent и ChangeEvent слушатели помещаются в отдельные внутренние классы, а слушатель события ItemEvent создается прямо на месте, как анонимный внутренний класс. При возникновении события информация об инициаторе выводится в консоль приложения. При щелчке на кнопке слушатель события определяет имя нажатой кнопки, используя метод getActionCommand() класса ActionEvent. Этот метод применяется для того, чтобы при обработке событий от нескольких кнопок в одном слушателе можно было их отличить. Событие ItemEvent не возникает вовсе, поскольку оно «работает» только с флажками, переключателями и другими компонентами, имеющими состояние, а кнопки его просто игнорируют.

Пример использования Action при создании JButton

В примере создаются две кнопки, которые выполняют одно и то же действие, и, соответственно, обладают одним и тем же набором параметров. Чтобы не дублировать код для настройки этих кнопок, создается один экземпляр команды SimpleAction, который и передается кнопкам.

SimpleAction расширяет абстрактный класс AbstractAction, имеющий поддержку слушателей PropertyChangeListener, которые оповещаются об изменениях в параметрах команды. Кнопки выступают в роли таких слушателей, что и позволяет им быть в курсе всех изменений и вовремя отображать их на экране. Все сводится к настройке параметров команды (обычно это производится в конструкторе) и определению метода actionPerformed(), отвечающего за обработку событий.

Параметры команды хранятся в виде пар «ключ-значение», где ключ — одна из строк, определенных в интерфейсе Action. Эта строка показывает, какой именно параметр команды хранится в паре. Для того чтобы изменить параметр, используется метод putValue().

Параметры интерфейса Action

  • NAME
    Определение надписи, которая будет выведена на кнопке или в меню;
  • SHORT_DESCRIPTION
    Определение всплывающей подсказки;
  • MNEMONIC_KEY
    Определение мнемоники;

Конечно, это не полный список ключей. Можно установить и несколько других параметров, в том числе иконку. Полный список можно найти в интерактивной документации Java.

Интерфейс примера представлен на следующих двух скриншотах.


В методе actionPerformed() определяется источник, вызвавший событие кнопки JButton. Если это кнопкам button1, то меняется ее наименование и она блокируется (скриншот справа).

Мнемоники

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

Для обеспечения доступа пользователя к визуальному компоненту с помощью клавиатуры следует использовать следующие методы класса AbstractButton :

  • setMnemonic(). Определение мнемоники, то есть определение клавиши символа в сочетании с управляющей клавишей (Alt) будет вызывать нажатие кнопки. Можно просто указать символ (в одинарных кавычках, регистр не учитывается), а можно использовать константы из класса Java.awt.event.KeyEvent.
  • setDisplayedMnemonicIndex(). Этот метод появился в выпуске JDK 1.4 после жалоб разработчиков на невозможность управлять тем, какой из символов надписи кнопки будет подчеркиваться, то есть символизировать наличие мнемоники , если в надписи есть несколько одинаковых символов.

Пример определения мнемоники кнопки JButton :

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

Поддержка двух состояний встроена в класс выключателя JToggleButton, от которого, в свою очередь, унаследованы классы флажков и переключателей.

Выключатель JToggleButton

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

Группы элементов управления ButtonGroup

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

Переключатели JRadioButton

Переключатель JRadioButton унаследован от выключателя JToggleButton и отличается от него только внешним видом. JRadioButton используют, как правило, при объединении нескольких переключателей в группу и реализации выбора «один из многих». По одиночке в интерфейсе их практически не используют; обычно эту роль исполняют флажки.

Флажки JCheckBox

Флажки в библиотеке Swing реализуются классом JCheckBox. Они, также как и переключатели, отличаются от выключателей только внешним видом. Флажки используются там, где нужно предоставить пользователю возможность что-то включить или выключить. Они также могут группироваться. Но, в отличие от JRadioButton, никогда не реализуют выбор «один из нескольких», а всегда позволяют выбрать несколько равноценных вариантов.

Рассмотрим пример, который включает все перечисленные элементы управления.

Интерфейс приложения представлен на следующих двух скриншотах. На левом скриншоте кнопка JToggleButton отпущена, панель panelRadio «открыта», в панели размещены кнопки JRadioButton. Панель panelCheck «скрыта». На правом скриншоте кнопка JToggleButton нажата, панель panelRadio «скрыта», панель panelCheck «открыта», в панели размещены кнопки JCheckBox.


В примере обработка события «изменения состояния кнопки» JToggleButton выполняется в методе itemStateChanged слушателя ItemListener. В зависимости от состояния нажатия кнопки изменяется название кнопки и «окрывается/скрывается» одна из панелей.

Архив примеров

Исходные коды примеров, рассмотренных на странице, можно скачать здесь (4.28 Кб).


Привет!

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

Что будет происходить?

Так как цель у меня — разобраться с JavaFX, нужно придумать какую-то функцию у нашего окна. Идея такая: создадим набор людей (предположим, что они работают в какой-то компании), для каждого из которых будет известно имя, возраст, зарплата и семейное положение. Наше окно, во-первых, будет выводить информацию о каждом из них, во-вторых, изменять зарплату какого-либо сотрудника, в-третьих, иметь возможность добавлять нового сотрудника, и, наконец, в-четверных, будет способно фильтровать сотрудников в зависимости от значений их атрибутов. В результате должно получиться что-то по типу этого:


Начинаем

Перво-наперво создаем главный класс Company, откуда будет происходить запуск приложения:


В этом классе будем расширять возможности класса Application. Из него нам нужен главным образом метод start(), в котором будет происходить основное действие (будем пропускать ошибки, возникающие в этом методе; другими словами, если что-то пойдет не так, наше окно не закроется, но в консоли появится StackTrace ошибки):
Отлично. Для того, чтобы работать с представителями сотрудников компании, создадим класс User: объекты этого класса и будут выступать в роли сотрудников.

Создаем

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


Что мы только что сделали: мы добавили сцену (scene) размером , дали ей название «Company». На нашей сцене присутствует группа root, которая по своей сути является «контейнером», который будет содержать в себе все кнопки.

Добавим выпадающий список с нашими сотрудниками. Создадим HBox, в который положим наш выпадающий список ComboBox userBox и кнопку, которая будет выдавать информацию о сотруднике (сам HBox поместим в VBox):



HBox — это набор кнопок, текстов, полей для ввода, каждый объект которого расположен последовательно горизонтально. Аналогичный ему, VBox является тем же самым, но хранит свои объекты (children) по вертикали. Мы будем использовать следующую схему: создатим VBox, в который будем класть несколько HBox'ов, в каждый из которых положим последовательность кнопок и полей.

ComboBox — это сам просто выпадающий список.

Теперь мы хотим создать кнопку, которая будет выдавать информацию о выбранном сотруднике. Добавим саму кнопку (Button) и текстовое поле (TextField), в которое будет выводиться текст. Эти два объекта добавим в HBox:



Но пока эта кнопка ничего не делает. Чтобы она что-то делала, необходимо ей присвоить действие:



Дальнейшие действия

Абсолютно аналогичным образом добавляем еще два HBox'а: во втором будет происходить изменение зарплаты, в третьем — добавляние нового сотрудника. В силу того, что логика здесь абсолютно та же самая, пропустим объяснения этих моментов и сразу покажем результат:


Фильтры

Теперь добавим «фильтрацию» сотрудников по признакам. Опять же, списки для фильтров будем добавлять с использованием ComboBox по той же самой логике.



Класс Company (главный)
Класс User

Что это было

Сама по себе программа не представляет никакой полезности и была написана исключительно для того, чтобы познакомиться с JavaFX и ее инструментами. В некотрых местах, например, при изменении зарплаты, не учитываются варианты, когда не выбран пользователь, или когда введена строка: в эти случаях будет появляться ошибка. То же самое касается полей, куда вводится информация при добавлении новых сотрудников. И, наконец, ошибка будет возникать, если не выбрано какое-то значение в любом из выпадающих списков. При желании, каждый может добавить свой «обход» этих моментов.

При написании фильтров, кстати, я использовал небезызвестные StreamAPI и -выражения, которые сокращают код, добавляют в него легкость понимания и свой шарм.

Давно не писал настольных приложений на Java вообще и с использовании Swing в частности. Однако, возникла необходимость немного по GUIть. В качестве инструмента выбрал IntelliJ IDEA Community edition, 2016.1 версии.

Взялся ваять и, естественно, первое, на что налетел — хотя со времён Borland Java Builder 2006 воды утекло немало, экранные интерфейсы создавать проще не стало, скорее наоборот. А одной из причин выбора IDEA было как раз наличие Swing дизайнера «из коробки», однако как им пользоваться с ходу решительно непонятно — форма генерится, класс создаётся, создаются переменные контролов из дизайнера… но и только: при создании нашего класса форма на экране не появляется

Пошарил интернет, информации приблизительно ноль. Народ говорит, мол, «создавай и — вперёд!». Хм…

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

Создание Swing GUI форм средствами JetBrains IntelliJ IDEA 2016.1

Во-первых, для понимания процесса лучше начать с того. что зайти в меню IDEA «File -> Settings» — там «Editor -> GUI Designer» и установить флажок Generate GUI Into: в Java source code. (это немного поможет пониманию процесса на первом этапе — потом можно будет убрать обратно).

image

Далее открываем дерево исходного кода своего проекта и кликаем правой кнопкой мыши на любую папку или файл исходного кода java и выбираем «New -> Dialog» — вводим имя класса для формы.

image

В итоге нам действительно сгенерили класс-наследник JDialog (который можно создать и использовать) и форма к нему.
Запускаем наш проект на выполнение и… о ужасчудо! при компиляции IDEA добавляет в конец нашего файла некоторый дополнительный код.


Несложно догадаться, что вся наша Swing-овая форма конфигурируется в автогенерируемом методе $$$setupUI$$$.

Вспомните настройку, которую мы установили в самом начале — «GUI Into: -> Java source code». Если её не ставить, то этот метод просто будет появляться напрямую в _class_ файле, минуя java-файл (декомпилируйте его, если сомневаетесь — я это сделал). Соответственно, можете вернуть настройку «GUI Into:» к первоначальному виду, чтобы этот код (который всё равно редактировать настоятельно не рекомендуют) не мозолил глаза.

Теперь, когда мы поняли, как оно работает, перейдём к созданию прочих форм — необязательно диалогов.

Опять правой кнопкой мыши кликаем на папку или файл исходного кода, выбираем «New -> GUI Form» — вводим имя класса для формы.

Генерится класс и форма к нему. Накидываем на форму несколько контролов. В GUI дизайнере смотрим имя корневого элемента (обычно panel1, если IDEA не задала имя, а такое бывает, задайте принудительно — я для наглядности назвал rootPanel).

image

Переходим к исходному коду нашего класса.

Итак:
1. Добавляем для нашего класса наследование «extends JFrame»;
2. Добавляем конструктор класса со строками:

Всё. Форма готова к употреблению. Остальное смотрите в многочисленных инструкциях по Swing.

P.S. Как вариант, можно не наследовать наш класс от JFrame, а создать конструктор вида:

Как создать графический интерфейс с JavaFX, используя разметку FXML и SceneBuilder.

Все посты в серии о JavaFX:

Традиционный способ

Просто напоминание — код выглядел так:


Как видите весь пользовательский интерфейс создан в Java коде.

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

У класса явно нет единой ответственности. Сравните это, например, с веб-интерфейсом, где каждая страница имеет четко разделенные задачи:

  • HTML — это структура
  • CSS — это визуальные эффекты
  • JavaScript — это поведение

Представляем FXML

Очевидно, что иметь весь код в одном месте не очень хорошая идея. Вам нужно как-то структурировать его, чтобы его было легче понять и сделать более управляемым.

В действительности есть много шаблонов дизайна для этого. Как правило, в конечном итоге вы приходите к варианту «Model-View-Whatever» — это что-то вроде «Model View Controller», «Model View Presenter» или «Model View ViewModel».

Можно часами обсуждать плюсы и минусы разных вариантов — давайте не будем делать это здесь. Более важно то, что с JavaFx вы можете использовать любой из них.

Это возможно потому, что в дополнение к процедурной конструкции вашего пользовательского интерфейса вы можете использовать декларативную разметку XML.

Оказывается иерархическая структура XML — это отличный способ описать иерархию компонентов в пользовательском интерфейсе. HTML работает достаточно хорошо, верно?

Формат XML, специфичный для JavaFX, называется FXML. В нем вы можете определить все компоненты приложения и их свойства, а также связать их с контроллером, который отвечает за управление взаимодействиями.

Загрузка FXML файлов

Итак, как мы можем изменить наш метод запуска для работы с FXML?


Здесь root представляет корневой компонент вашего пользовательского интерфейса, остальные компоненты вложены в него.

Метод load имеет generic возвращаемое значение, поэтому вы можете указать конкретный тип, а не Parent. Далее, вы получаете доступ к компонентно-ориентированным методам. Однако, это делает ваш код более хрупким. Если вы измените тип корневого компонента в вашем FXML, приложение может перестать работать во время выполнения, но при этом во время компиляции не будет ошибок. Это происходит потому, что теперь есть несоответствие типа, объявленного в вашем FXML и в загрузчике Java FXML.

Создание FXML файла

Теперь мы знаем, как загрузить файл FXML, но нам все еще нужно его создать. Файл должен иметь расширение .fxml. В Maven проекте, вы можете поместить этот файл в папку ресурсов или FXMLLoader может загрузить его с внешнего URL-адреса.

После создадания файла в его первой строке необходимо ввести декларацию XML:

Импорт

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

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

Добавление компонентов

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


Конечно, метка в качестве корневого компонента — это не очень реалистичный пример. Обычно предпочтительнее использовать какой-то макет (layout), который является контейнером для нескольких компонентов и организует их расположение. Мы рассмотрим макеты позже в этой серии, а сейчас давайте просто воспользуемся простым VBox, который размещает свои дочерние элементы вертикально друг над другом.

FX Namespace

Существует пара элементов и атрибутов FXML, которые по умолчанию недоступны. Вам нужно добавить пространство имен (Namespace) FXML, чтобы сделать их доступными. Его необходимо добавить к корневому компоненту:


Теперь можно использовать новые элементы из пространства имен fx. Давайте попробуем добавить уникальные идентификаторы в наши компоненты:


Атрибут fx:id является уникальным идентификатором компонента, который можно использовать для ссылки на компонент из других частей нашего FXML и даже из нашего контроллера.

Скрипты

Наше приложение пока статично. Есть несколько меток и кнопка, но приложение не делает ничего динамического.

Давайте отреагируем на нажатие нашей кнопки и изменим заголовок с «Click me!» на «Click me again!».

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


Обратите внимание на fx:id, это идентификатор, который будет использоваться позже для ссылки на кнопку.

Теперь нужно предоставить функцию, которая будет вызвана для обработки события. Ее можно определить внутри тега fx:script. Важно то, что вы можете использовать различные языки для написания скрипта, JavaScript, Groovy или Clojure. Давайте посмотрим пример на JavaScript:


Заметьте, что мы ссылаемся на наш компонент Button с помощью идентификатора mainButton, который был объявлен так:


Также необходимо указать, какой язык сценариев вы используете в файле FXML:


Давайте рассмотрим полный текст примера:


Должен ли я использовать это?

В приведенном выше примере показано, как ссылаться на компоненты с помощью fx:id и как добавить простое поведение с помощью скрипта на JavaScript. Неужели это то, что вы должны на самом деле делать?

Ответ — в большинстве случаев нет. Есть несколько проблем с таким подходом. Причина, по которой введен FXML, была разделение интересов — чтобы отделить структуру и поведение пользовательского интерфейса. В этом скрипте снова вернулось поведение слитное со структурой пользовательского интерфейса. Более того, поскольку мы больше не работаем с кодом Java, а с XML, были утрачены все проверки кода во время компиляции и безопасность типов. Теперь все проблемы в приложении будут обнаружены во время выполнения, а не во время компиляции. Приложение стало очень хрупким и подверженым ошибкам.

Добавление контроллера

Итак, что можно сделать, чтобы получить четкое разделение интересов? Можно связать контроллер с нашим файлом FXML. Контроллер — это Java класс, который отвечает в приложении за обработку поведения и взаимодействия с пользователем. Таким образом можно вернуть безопасность типов и проверки времени компиляции.

Контроллер является POJO, он не должен расширять или реализовывать что-либо, а также не должен иметь никаких специальных аннотаций.

Как можно связать класс контроллера с нашим FXML? По существу, есть два варианта.

На Java

Вы можете создать экземпляр контроллера самостоятельно или использовать любые другие способы создания экземпляра, такие как инъекция зависимости. Затем просто загрузите вашим FXMLLoader.

В FXML

Вы можете указать класс вашего контроллера как атрибут fx:controller, который должен находиться в корневом компоненте.


Если вы объявляете свой класс Controller в FXML, он автоматически создается для вас. Этот подход имеет одно ограничение — в контроллере нужно создать конструктор без аргументов, чтобы позволит легко создавать новый экземпляр класса Controller.

Для получения доступа к экземпляру контроллера, созданного автоматически, можно использовать загрузчик FXML:

Вызов методов контроллера

Теперь, когда имеется контроллер, можно удалить скрипт и реализовть логику нажатия кнопок прямо в контроллере:


При нажатии на кнопку, она вызывает метод MainSceneController.buttonClicked(). Имейте в виду, что это работает, только если метод объявлен public. Если модификатор доступа более строгий, необходимо аннотировать метод аннотацией @FXML.

Внедрение компонентов в контроллер

Пока что мы просто печатаем на консоль. Что если мы снова захотим изменить текст нашей кнопки на «Click me again»? Как мы можем получить ссылки на компоненты в нашем контроллере?

К счастью, это легко. Помните эти атрибуты fx:id?


JavaFX пытается автоматически сопоставить компоненты с fx:id с полями определенным в вашем контроллере с тем же именем.

Предположим, у нас есть кнопка описанная выше с


JavaFX пытается внедрить объект кнопки в ваш контроллер в поле с именем mainButton:


Как и в предыдущих методах, ваши поля должны быть public или аннотированными @FXML.

Теперь, когда у нас есть ссылка на нашу кнопку, можно легко изменить ее текст:

Scene Builder

Написание вашей структуры GUI в XML может быть более естественным, чем в Java (особенно если вы знакомы с HTML). Тем не менее, до сих пор это не очень удобно. Хорошей новостью является то, что существует официальный инструмент под названием Scene Builder, который поможет вам в создании пользовательского интерфейса. В двух словах, это графический редактор для вашего графического интерфейса.


В редакторе имеется три основных области:

  1. В левой части отображаются доступные компоненты, которые можно перетащить в среднюю часть. Она также содержит иерархию всех компонентов в вашем пользовательском интерфейсе, поэтому вы можете легко перемещаться по ней.
  2. Средняя часть — это ваше приложение, отображаемое на основе вашего файла FXML.
  3. Справа находится инспектор текущих компонентов. Здесь вы можете редактировать различные свойства выбранного текущего компонента. Любой компонент, выбранный в средней части иерархии, отображается в инспекторе.

Standalone

Scene Builder можно загрузить как отдельное приложение, которое можно использовать для редактирования FXML файлов.

Интеграция с IntelliJ IDEA

В качестве альтернативы, Scene Builder предлагает интеграцию с IDE.

В IntelliJ IDEA вы можете нажать правой кнопкой мыши на любом FXML файле и затем выбрать опцию меню «Открыть» в SceneBuilder.

В качестве альтернативы, IntelliJ IDEA интегрирует SceneBuilder непосредственно в IDE. Если вы откроете файл FXML в IDEA, в нижней части экрана появятся две вкладки


В IntelliJ IDEA можто настроить расположение исполняемого файла SceneBuilder:

Settings → Languages & Frameworks → JavaFX → Path to SceneBuilder

Что дальше


В следующем посте из нашей серии будут рассмотрены некоторые основные макеты (layout), которые можно использовать для организации компонентов GUI приложения на JavaFX.

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

Все окна библиотеки Swing — а к ним относятся окно без рамки JWindow, окно с рамкой JFrame и диалоговое окно JDialog — являются исключением из правила, согласно которому все компоненты Swing представляют собой легковесные компоненты и унаследованы от базового класса JComponent. Окна Swing являются тяжеловесными контейнерами для размещения в них легковесных компонентов, которые операционная система не видит.

Наиболее полезные JFrame методы

МетодыОписание
setLocation()Эта группа методов позволяет задать позицию и размеры окна на экране. setLocation() задает позицию окна, setSize() позволяет указать его размеры, а с помощью setBounds() можно сразу задать прямоугольник, который займет ваше окно на экране
setSize()
setBounds()
раск()Позволяет «упаковать» имеющиеся в окне компоненты, так чтобы они занимали столько места, сколько им необходимо. Компоненты при вызове этого метода переходят в «видимое» состояние, хотя и не появляются на экране до вызова одного из следующих методов
show()Отображение окна на экране. После вызова этих методов компоненты переходят в «видимое» состояние и начинают обслуживаться очередью событий. Метод show() к тому же проводит валидацию содержащихся в окне компонентов
setVisible()
dispose()Убирает окно с экрана (если оно в момент вызова метода видимо) и освобождает все принадлежащие ему ресурсы.

Окно JWindow

«Родителем» всех окон Swing является окно без рамки и без элементов управления JWindow.

Класс JWindow представляет собой окно без рамки и без элементов управления, предназначенных, к примеру, для его закрытия или перемещения. Данный тип окна дает минимальные возможности по своей настройке, в отличие от чаще всего используемого окна JFrame. Окно без рамки не часто требуется в программах. Однако в отдельных случаях оно может быть полезно, особенно в тех случаях, когда необходимо ненадолго вывести на экран какую-либо информацию типа заставки программы или подсказку для пользователя, и управлять окном с этой информацией не нужно.

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

Рассмотрим пример JWindowTest. Основная идея использования окна без рамки JWindow заключается в копировании части "изображения рабочего стола" в окно приложения. Благодаря появившемуся в пакете JDK 1.3 классу Robot можно "снимать" экранную копию рабочего стола.

Пример JWindow

В этом примере приложение наследуем от окна JWindow, чтобы удобнее вызывать методы этого класса и добавлять в окно компоненты. Объект Robot необходимо создавать в блоке try . catch, т.к. его создание может быть запрещено менеджером безопасности, используемым виртуальной машиной Java. Впрочем, нам нарушение безопасности не грозит, потому что мы создаем отдельное приложение, а не апплет.

Вырезаем часть изображения "рабочего стола" методом createScreenCapture() в стороне он местоположения нашего окна. Затем в панель содержимого окна добавляется компонент ImageDraw, который и отображает вырезанное изображения рабочего стола. После вывода окна на экран программа засыпает на 10 секунд, а потом заканчивает свою работу.

Скриншот рабочего стола с интерфейсом окна примера JWindow представлен на следующем рисунке.


Прежде чем производить настройку окна, в примере JWindowTest вызывается конструктор базового класса ключевым словом super() без параметров. На самом деле окна без рамки JWindow обязательно требуют при создании указывать своего «родителя» — окно с рамкой JFrame,что не всегда может быть неудобно. Специально для таких случаев в класс JWindow был добавлен конструктор без параметров, который создает вспомогательное невидимое окно JFrame и использует его как «родителя». После этого все окна без рамки, созданные таким образом, задействуют только это окно и экономят ресурсы.

Следует также отметить, что с помощью конструктора без параметров создается окно JWindow, неспособное получать фокус ввода. Чаще всего именно такое поведение необходимо (ведь панелям инструментов, всплывающим заставкам и меню фокус ввода не нужен). При необходимости получения фокуса ввода, используйте метод setFocusableWindowState(true).

Окно JFrame

Окно JFrame наследует свойства класса JWindow и представляет собой наиболее часто используемое в приложениях окно «общего назначения». Основные отличия окна JFrame от JWindow :

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

Для размещения компонентов пользовательского интерфейса в подавляющем большинстве приложений применяется класс JFrame. Разработчики Swing определили специальный метод закрытия окна setDefaultCloseOperation, существенно упрощающий эту операцию. Рассмотрим простой JFrame пример (JFrameWindowListener) с обработкой события закрытия окна.

JFrame пример

В примере создается окно JFrame с определением заголовка в конструкторе базового класса. Для определения титульной строки окна можно также использовать метод setTitle() класса JFrame.

Прежде чем задать размеры окна и отобразить его на экране, вызывается метод setDefaultCloseOperation(). Данный метод позволяет указать, какое действие будет произведено при предварительной обработке события processWindowEvent() перед закрытием окна. По умолчанию используется константа HIDE_ON_CLOSE, убирающая окно с экрана при его закрытии. Можно использовать значение EXIT_ON_CLOSE, которое указывает, что при закрытии окна необходимо закончить работу приложения.

В примере методу setDefaultCloseOperation передается константа DO_NOTHING_ON_CLOSE - ничего не делать при закрытии окна. К окну JFrame подключается слушатель и обработка события закрытия окна выполняется в методе windowClosing. Алгоритм обработки построен таким образом, что окно закрывается при третьей попытке. Номер попытки отображается в метке интерфейса.

Скриншот рабочего стола с интерфейсом окна нашей программы представлен на следующем рисунке.


Для определения иконки окна необходимо использовать метод setIconImage(). Иконка располагается на кнопке свернутого окна или в заголовке окна в нормальном состоянии.

Из дополнительных возможностей окна с рамкой JFrame следует упомянуть о его способности «прятать» свои «украшения»: рамку и элементы управления окном. Делает это метод JWindow.

События окон, WindowListener, WindowFocusListener

Окна Swing (JWindow, JFrame, JDialog) поддерживают два типа событий :

  • WindowListener - позволяет узнать об изменениях в состоянии окна;
  • WindowFocusListener - сообщает о получении или потере компонентами окна фокуса ввода

Полный список методов данных слушателей можно найти в интерактивной документации Java.

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

К фрейму JFrame можно подключить слушателя окна, созданного на основе WindowAdapter (чтобы не реализовывать все определенные в интерфейсе WindowListener методы) и переопределить метод windowClosing, как это представлено в следующих строках кода :

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

Диалоговое окно JDialog

Диалоговые окна чаще всего используются в приложениях для получения дополнительной информации с целью установки параметров приложения, вывода важной вспомогательной/отладочной информации. Диалоговые окна, как правило, создаются модальными (modal), блокирующими доступ к остальным окнам приложения, пока пользователь не закончит работу с модальным диалоговым окном. Модальные диалоговые окна располагаются поверх основного окна приложения. Внешний вид диалоговых окон мало отличается от окон с рамкой JFrame, но обычно у них меньше элементов управления окна (чаще всего, имеется только кнопка закрытия окна) и отсутствует системное меню.

В Swing диалоговые окна реализуются классом JDialog, унаследованном от базового класса окон JWindow и позволяющим создавать как обычные, так и модальные диалоговые окна. JDialog поддерживает как и JFrame закрытие окна, а в остальном сходен с другими окнами Swing.

При создании диалоговых окон Swing необходимо указать «родительское окно», которым может быть окно с рамкой JFrame или другое диалоговое окно JDialog. Имеется также конструктор, не требующий «родительского» окна, но использующий вспомогательное прозрачное окно, о котором было сказано на странице «Окно без рамки JWindow».

JDialog пример создания диалоговых окон

В примере создаем окно с рамкой JFrame, в панели содержимого которого размещается две кнопки JButton. По нажатию на кнопки создаются диалоговые окна в отдельном методе createDialog(). Диалоговое окно с заданным заголовком JDialog может быть модальным и немодальным. Программа позволяет создать несколько немодальных окон одновременно, но только одно модальное. Немодальные окна не блокируют работу с основным окном приложения. При закрытии диалогового окна используется константа DISPOSE_ON_CLOSE, удаляющую окно после закрытия.

Интерфейс работы примера JDialog представлен на следующем скриншоте.


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

Оформление окон

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

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

В классах JFrame и JDialog имеется статический метод setDefaultLookAndFeelDecorated(), обеспечивающий возможность оформления всех создаваемых окон.

Пример оформления окон : JDialog decoration

В примере создается простое окно с рамкой и диалоговое окно. Перед создания окон вызывается метод setDefaultLookAndFeelDecorated(), означающий, что для создаваемых окон JFrame и JDialog потребуется специальное оформление. Далее определяются размеры окон и они выводятся на экран.

Интерфейс примера окон, оформленных с внешним видом Metal, представлен на следующем скриншоте.


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

Исходные коды примеров, рассмотренных в тексте страницы, можно скачать здесь (3.54 Кб).

Читайте также: