Как сделать круглую кнопку javafx

Обновлено: 05.07.2024

Однажды у меня возникла идея, написать небольшое настольное приложение для своих нужд — что-то типа небольшого словаря для изучения иностранных слов — и я начал ломать голову, а как бы мне это сделать? Естественно, первое, что мне пришло в голову — Swing. Все наверняка слышали о Swing . Это библиотека для создания пользовательских, графических интерфейсов. В связи с тем, что наш горячо любимый Oracle еще не полностью отказался от Swing, он не считается устаревшим, и приложения на нем по-прежнему работают. Однако он больше не модернизируется Swing, и ребята из Oracle дали нам понять, что за JavaFX будущее. Да и по сути, JavaFX использует компоненты Swing как поставщика услуг)

Что такое JavaFX?

Особенности JavaFX:

  • JavaFX изначально поставляется с большим набором частей графического интерфейса, таких как всякие там кнопки, текстовые поля, таблицы, деревья, меню, диаграммы и т.д., что в свою очередь сэкономит нам вагон времени.
  • JavaFX часто юзает стили CSS, и мы сможем использовать специальный формат FXML для создания GUI, а не делать это в коде Java. Это облегчает быстрое размещение графического интерфейса пользователя или изменение внешнего вида или композиции без необходимости долго играться в коде Java.
  • JavaFX имеет готовые к использованию части диаграммы, поэтому нам не нужно писать их с нуля в любое время, когда вам нужна базовая диаграмма.
  • JavaFX дополнительно поставляется с поддержкой 3D графики, которая часто полезна, если мы разрабатываем какую-то игру или подобные приложения.
  • Stage — по сути это окружающее окно, которое используется как начальное полотно и содержит в себе остальные компоненты. У приложения может быть несколько stage, но один такой компонент должен быть в любом случае. По сути Stage является основным контейнером и точкой входа.
  • Scene — отображает содержание stage (прям матрёшка). Каждый stage может содержать несколько компонентов — scene, которые можно между собой переключать. Внутри это реализуется графом объектов, который называется — Scene Graph (где каждый элемент — узел, ещё называемый как Node ).
  • Node — это элементы управления, например, кнопки метки, или даже макеты (layout), внутри которых может быть несколько вложенных компонентов. У каждой сцены (scene) может быть один вложенный узел (node), но это может быть макет (layout) с несколькими компонентами. Вложенность может быть многоуровневой, когда макеты содержат другие макеты и обычные компоненты. У каждого такого узла есть свой идентификатор, стиль, эффекты, состояние, обработчики событий.

JavaFX: примеры использования

Знакомство с JavaFX SceneBuilder

Введение в Java FX - 8

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

Небольшое отступление. JavaFX уроки

  • delete — по индексу удаляем выбранную(выделенную) собаку;
  • edit — создаем новую собаку с переданными данными, и задаем ее вместо той которая была до этого;
  • create — создаем новую собаку и дергаем метод вызова окна создания, передав новый объект, и после закрытия которого если имя не null, то сохраняем нового питомца.

Введение в Java FX - 14

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

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

Imgur

Восьмая версия еще особенно хороша тем что ей не надо админских прав и можно ставить в компьютерных классах

Imgur

Imgur

Imgur

по завершению установки запустится SceneBuilder

Imgur

но он нам пока не нужен, так что можно его закрыть.

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

Imgur

назову его CustomTypeGUI

Imgur

получаем такую структуру проекта:

Imgur

Принцип организации javafx интерфейса

Кликнем дважды на файлик sample.fxml чтобы открыть его и увидим там что-то такое:

fxml – это такой аналог html, только в рамках java, тут даже есть всякие импорты. И есть тэги, определяющие что будет отображаться. Тут к нас пока только один тэг GridPane, которые используется для выравнивания компонент по сетке.

Правда пока выравнивать нечего, так что пока это по сути пустой контейнер.

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

И так, попробуем запустить программу. Увидим что-то такое

Imgur

Откуда же это все взялось? А на самом деле ничего хитрого нет. Открываем файлик Main.java и видим

Добавляем кнопку

Вернемся к файлу sample.fxml. Теперь запустим SceneBuidler, выбираем Open Project

Imgur

и открываем наш файлик. Увидим что-то такое

Imgur

Перетянем теперь кнопку на форму. Так как пока у нас пустой GridPane наша форма выглядит как пустота. Но тянуть можно:

Сохраним перетянутое Ctrl+S и переключимся обратно в Idea. И глянем что у нас выросло с файлике sample.fxml. Там у нас будет такое:

Видим, что тут много чего поменялось. Появились какие-то Constraints (это так называем ограничения на размеры колонок и строк, нам они пока не интересны).

Ну и главное, что тут появился тег children и внутри него наша кнопочка

  • text – это то что написано на кнопке
  • mnemonicParsing – это специальный тег для обработки горячих клавиш, но нам это сейчас неинтересно, так что можно игнорировать

Можно попробовать запустить:

Imgur

ура, есть кнопочка! =)

Добавляем реакцию на нажатие

Но кнопка — это не кнопка если нажимая на нее ничего не происходит. Попробуем добавить реакцию на клик.

Переключимся на файл Controller.java:

Помните я упомянул атрибут fx:controller=”sample.Controller” внутри sample.fxml, так вот мы сейчас в том самом классе на который указывал этот атрибут. За счет него происходит связывание интерфейса и логики (контроллера).

Чтобы добавить реакцию на клик достаточно сделать следующие операции.

Можно даже попробовать запустить. И потыкать кнопку

Imgur

хехе, очевидно ничего не произойдет. Мы ж пока функцию не привязали =)

А теперь переключимся на SceneBuilder и привяжем кнопку к функции

не забудем сохранить, и запустим проект по-новому

Кстати можно открыть файлик sample.fxml и глянуть что там произошло:

Читаем значение из текстового поля

Ну тыкать на кнопочки и выполнять всякие функции — это конечно важное умение. Но не менее важно уметь считать значение из поля, например, текстового.

Делается это в некотором роде проще чем привязка кнопки.

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

Что я сделаю? Сначала создам в классе поле, через которое образуется связь

теперь переключимся на SceneBuilder, перетащим текстовое поле на форму, а затем привяжем его к нашему классу, путем указания свойства fx:id:

если вдруг у вас в этом поле ничего не высветилось, то можете смело вписать туда вручную txtInput.

Сохраним в SceneBuilder и вернемся обратно в Idea. Если глянуть в файлик fxml то увидим

Imgur

теперь вернемся в наш Controller и подправим метод showMessage:

Меняем значения текстового поля

О, давайте еще научимся изменять значение в списке, но тут все просто

В принципе вот и вся наука =)

  • добавил поле в контроллер
  • добавил объект в SceneBuilder
  • связал через fx:id, либо связал с методом.

Теперь можно пилить что-нибудь посложнее.

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

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

К тому же в JavaFX есть много хитрых особенностей, которые в WindowsForms не встречалось.

И так, попробуем добавить выпадающий список. Действуем по выше предложенному алгоритму. Сперва добавим поле в контроллер:

теперь добавляем на форму

затем подключаем по fx:id

Imgur

не забываем сохраниться в SceneBuilder.

Запускаем и проверяем:

Imgur

Ура! Есть список! Правда пустой пока…

Заполняем список (интерфейс Initializable)

И вот незадача, как же его заполнить? У нас по сути голый класс Controller, без ничего. Давайте попробуем в конструкторе:

запускаем и… бдыщь

Imgur

суть стенаний виртуальной машины заключается в том, что comboBox нулевой. А нулевой он потому что привязка полей помеченных декоратором @FXML происходит уже после вызова конструктора, где-то в терньях фреймворка JavaFX.

Поэтому добавление элемента в конструкторе не прокатит.

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

загоним теперь в метод initialize наш вызов добавления элемента

Imgur

Добавляем реакцию на переключения списка

Давайте сначала добавим еще несколько элементов

Есть как минимум два способа добавить реакцию на переключения

Через SceneBuilder

Imgur

не забываем сохраниться.

2) Затем в IDEA тыкаем правой кнопкой мыши на название метода

Imgur

выбираем первый пункт Show Context Actions, а затем:

Imgur

3) Нас перекинет в контроллер где мы увидим новодобавленный метод

в принципе, его можно было и руками добавить >_>

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

Через лямбда-функцию

Ну тут просто в методе инициализации привязываете лямбда-функцию к реакции на изменение свойства.

Я на лекции расскажу что тут происходит на самом деле

Еще может пригодится чекбокс, для вывода всяких булевых значений. Добавим его на форму

добавим в Controller:

теперь подключим checkbox к форме


ну теперь мы можем, например, управлять им кликая на кнопку:

ой, забыли кнопке указать другую функцию


Вот теперь красота! =)

кстати если хотите текст поменять то правьте поле Text:


Одним из важных принципов при разработке приложений, а особенно GUI приложений заключается в том, что состояние формы (значения в полях, размеры и положение) после закрытия приложения и при последующем открытии должно сохранятся.

Как правило для хранения состояния приложения используют простые файлы в каком-нибудь распространённом формате типа *.xml, *.ini, *.json

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

Подключаем обработчик закрытия формы

Мы будем сохранять в момент закрытия формы.

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

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

Там есть понятие stage (англ. состояние, сцена как место где происходят события), которое представляет собой окно приложения и scene (англ. тоже сцена, но уже в качестве события) которая, если немного упростить, представляет собой fxml файлик + контроллер.

Ну и ясно что именно к scene привязывается класс Controller. И так как scene за окно формы (то бишь stage) не отвечает, то из него и нельзя получить прямого доступа к событию закрытия окна.

Но можно получить не прямой. Для этого надо поймать событие закрытия формы (то бишь stage) и проксировать его в Controller. Делается это так:

Сначала пойдем в контроллер и создадим функцию которая должна будет вывязываться при закрытии формы. Такую:

теперь идем в Main и делаем магические пассы:

Сохраняем состояние формы в файл

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

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

И так создаем новый класс

Imgur

фиксируем в него поля

теперь идем в Controller и в методе закрытия формы прописываем:

а теперь добавляем сериализацию в файл. Тут все просто

теперь проверяем как работает

Так-так, файлик появился. У меня внутри такие строчки:

теперь попробуем добавить чтение из файла. Чтение стало быть делаем в инициализаторе:

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


Мой пользовательский класс кнопок должен расширяться JButton или же BasicButtonUI так что это может быть использовано повторно.

4 ответа

Вы должны создать свой собственный компонент для этого.

Переопределите метод paintComponent на JPanel, а внутри метода paintComponent нарисуйте (т.е. залейте) прямоугольник с закругленными углами2D серым цветом:

(Последние два значения определяют кривизну. Поиграйте, пока не получите желаемое)

Теперь переместите x,y и уменьшите ширину и высоту, чтобы при рисовании следующего прямоугольника он находился внутри серого прямоугольника. Установите цвет графики на синий, затем сделайте что-то вроде этого:

Вам также нужно будет добавить текст. Добавление текста требует позиции x и y. Точное положение x и y может быть сложно вычислить, поэтому вам может понадобиться использовать FontMetrics, чтобы получить больше информации о форме прямоугольника строки. Fontmetrics имеет такие методы, как stringWidth() и getHeight(), которые помогут вам определить, какими должны быть ваши x и y.

Наконец, вы должны иметь слушателя движения мыши на вашей панели. Слушатель должен найти, когда мышь находится над кнопкой, а затем перерисовать компонент.

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

Если он содержится, измените цвет, затем вызовите repaint() или updateUI() на панели.

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

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

Кнопки JButton

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

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

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

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

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

Метод 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
Событие о смене состояния возникает в компонентах, которые имеют несколько равноценных состояний (например, флажки и переключатели).

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

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

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

Параметры интерфейса 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

Флажки JCheckBox

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


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

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

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