Javafx — JavaFX. Взаимодействие контроллера с .fxml


Содержание

Вопрос по fxml, javafx, javafx-2, java, controller &#8211 Как создать несколько контроллеров javafx с различными файлами fxml?

я смотрел некоторые блоги и другие вопросы, связанные с переполнением стекаЯ не вижу прямого ответа на мой вопрос. Я создаю клиент javafx GUI, и я хочу, чтобы моя строка меню была одним контроллером в одном fxml, а затем я хочу, чтобы область содержимого была дополнительными файлами fxml. Экран входа в систему будет представлять собой один fxml, после экрана входа в систему будет отображаться основной контент приложения, который будет представлен в одном формате fxml. Как мне это сделать?

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

используя пользовательский класс Java в качестве fx: root и как fx: контроллер вашего файла FXML:http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm

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

Классический способ создания компонентов через FXMLLoader с вложенными контроллерами: сначала FXML, затем контроллер для каждой детали.

С этой техникой это: сначала контроллер, затем FXML для каждого компонента. И ты выигралt загружая FXML в FXML напрямую, вы импортируете свои пользовательские классы Java в FXML.

Это лучшая абстракция (не нужно знать, как компонент реализуется при импорте их в FXML), и помогает повторно использовать код, как если бы он реализовывал пользовательский виджет с поддержкой FXML. Чтобы сделать ваш компонент многоразовым, убедитесь, что ваша реализация нене иметь тесной связи с другими частями или использовать для этого IOC (например, с интеграцией Spring с JavaFX). Таким образом, вы сможете без проблем импортировать свой компонент в любую часть вашего приложения (так же, как виджет DateInput), и вы выиграете ».дубликат кода.

Получение доступа к элементам Controller в JavaFX из другого класса

28.11.2015, 01:35

Изменение компонента из другого класса JavaFx
есть панель с кнопкой, из другого класса задаю кнопке другой текст класс унаследовал ошибок в.

JavaFX: Получить объект с Controller
NetBeans сгенерил проект: есть SampleController.java Sample.fxml и «мой класс»(extends.

Получение доступа к элементам формы с другого namespace
Как получить доступ к данным с другого namespace using abc; namespace WindowsForm < class.

Получение доступа к переменным класса из другого класса
Как передать по ссылке переменную из класса А в метод класса В?

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

Javafx — JavaFX. Взаимодействие контроллера с .fxml

138946 просмотра

9 ответа

5801 Репутация автора

Как я могу передать параметры во вторичное окно в javafx? Есть ли способ связи с соответствующим контроллером?

Например: пользователь выбирает клиента из TableView и открывается новое окно с информацией о клиенте.

newStage будет новое окно. Проблема в том, что я не могу найти способ сообщить контроллеру, где искать информацию о клиенте (передавая id в качестве параметра).

Ответы (9)

8 плюса

3325 Репутация автора

Класс javafx.scene.Node содержит пару методов setUserData (Object) и Object getUserData ().

Который вы могли бы использовать, чтобы добавить свою информацию в узел.

Итак, вы можете вызвать page.setUserData (info);

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

Ознакомьтесь с документацией здесь: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Перед фразой «В первой версии handleButtonAction () помечен как @FXML чтобы позволить разметке, определенной в документе контроллера, вызывать ее. Во втором примере поле кнопки аннотировано, чтобы позволить загрузчику установить его значение. Метод initialize () также аннотирован. «

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

232 плюса

110663 Репутация автора

Рекомендуемый подход

Этот ответ перечисляет различные механизмы для передачи параметров в контроллеры FXML.

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

Для более крупных и сложных приложений было бы целесообразно выяснить, хотите ли вы использовать в своем приложении механизмы Dependency Injection или Event Bus .

Передача параметров напрямую от вызывающего к контроллеру

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

Что-то вроде следующего кода:

Новый FXMLLoader строится , как показано в примере кода , т.е. new FXMLLoader(location) . Расположение является URL-адресом, и вы можете создать такой URL-адрес из ресурса FXML:

Будьте осторожны, НЕ используйте функцию статической загрузки на FXMLLoader, иначе вы не сможете получить свой контроллер от своего экземпляра загрузчика.

Сами экземпляры FXMLLoader никогда ничего не знают об объектах домена. Вы напрямую не передаете доменные объекты приложения в конструктор FXMLLoader, вместо этого вы:


  1. Создайте FXMLLoader на основе разметки fxml в указанном месте
  2. Получить контроллер из экземпляра FXMLLoader.
  3. Вызвать методы на полученном контроллере, чтобы предоставить контроллеру ссылки на объекты домена.

Этот блог (другого автора) предоставляет альтернативный, но похожий пример .

Настройка контроллера на FXMLLoader

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

Чтобы установить контроллер на загрузчик (в JavaFX 2.x), вы НЕ МОЖЕТЕ также определить fx:controller атрибут в вашем файле fxml.

Из-за ограничения fx:controller определения в FXML, я лично предпочитаю получать контроллер из FXMLLoader, а не устанавливать контроллер в FXMLLoader.

Наличие контроллера, получающего параметры из внешнего статического метода

Использовать инъекцию зависимостей

FXMLLoader поддерживает системы внедрения зависимостей, такие как Guice, Spring или Java EE CDI, позволяя вам установить фабрику пользовательских контроллеров на FXMLLoader. Это обеспечивает обратный вызов, который можно использовать для создания экземпляра контроллера с зависимыми значениями, введенными соответствующей системой внедрения зависимостей. Существует пример интеграции FXML с системой внедрения зависимостей Spring (к сожалению, ссылка устарела, а содержимое пропало, если кто-нибудь знает подобный пример, пожалуйста, отредактируйте этот вопрос, чтобы ссылаться на него), хотя он немного более грубый, чем был бы использовать новые функции фабрики пользовательских контроллеров, доступные в JavaFX 2.2.

Действительно хороший, чистый подход к внедрению зависимостей иллюстрируется фреймворком afterburner.fx с примером приложения air-hacks, которое его использует. afterburner.fx использует Jav6 javax.inject для выполнения внедрения зависимостей.

Используйте шину событий

Грег Браун (Greg Brown), создатель и разработчик оригинальной спецификации FXML, часто предлагает рассмотреть возможность использования шины событий для связи между инстанцированными контроллерами FXML и другой логикой приложения.

EventBus — это простой, но мощный API публикации / подписки с аннотациями, который позволяет POJO взаимодействовать друг с другом в любом месте JVM без необходимости ссылаться друг на друга.

Последующие вопросы и ответы

на первом методе, почему вы возвращаете этап? Этот метод также может быть аннулирован, потому что вы уже дали команду show (); как раз перед возвращением стадии ;. Как вы планируете использование, возвращая этап

Это функциональное решение проблемы. Этап возвращается из showCustomerDialog функции, так что ссылка на него может быть сохранена внешним классом, который может захотеть что-то сделать, например, скрыть этап на основе нажатия кнопки в главном окне в более позднее время. Альтернативное объектно-ориентированное решение может инкапсулировать функциональность и ссылку на стадию в объекте CustomerDialog или иметь расширенную стадию CustomerDialog. Полный пример объектно-ориентированного интерфейса с настраиваемым диалоговым окном, инкапсулирующим данные FXML, контроллера и модели, выходит за рамки этого ответа, но может стать достойной записью в блоге для любого, кто хочет его создать.

Дополнительная информация предоставлена ​​пользователем StackOverflow с именем @dzim

Пример для инъекции зависимостей весенней загрузки

На вопрос о том, как это сделать «The Spring Boot Way», шла дискуссия о JavaFX 2, на которую я ответил в прикрепленной постоянной ссылке. Этот подход все еще действителен и протестирован в марте 2020 года на Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217

Иногда вы можете захотеть передать результаты обратно вызывающей стороне, и в этом случае вы можете проверить ответ на соответствующий вопрос:

плюса

879 Репутация автора

Вот пример использования контроллера, введенного Guice.

Вот конкретная реализация загрузчика:

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

7 плюса

73 Репутация автора

Вот пример для передачи параметров в документ fxml через пространство имен.

Определите значение External Text для переменной пространства имен labelText :

3 плюса

1235 Репутация автора

Это работает ..

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

2 плюса

175 Репутация автора

Вы должны создать один класс контекста.

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

и вы можете использовать его из всего приложения, просто используя

Теперь вы можете передать параметр на любой контроллер из всего приложения.

Автор: CTN Размещён: 22.10.2020 02:14

плюса

9 Репутация автора


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

7 плюса

3665 Репутация автора

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

В этом примере мы будем использовать 5 файлов:

  1. Main.java — просто используется для запуска приложения и вызова первого контроллера.
  2. Controller1.java — Контроллер для первого макета FXML.
  3. Controller2.java — Контроллер для второго макета FXML.
  4. Layout1.fxml — макет FXML для первой сцены.
  5. Layout2.fxml — макет FXML для второй сцены.

Все файлы перечислены полностью в нижней части этого поста.

Цель: продемонстрировать передачу значений из Controller1 в Controller2 и наоборот.

Ход программы:

  • Первая сцена содержит a TextField , a Button и a Label . Когда Button нажата кнопка, загружается и отображается второе окно, включая текст, введенный в TextField .
  • Во второй сцене также есть a TextField , a Button и a Label . На Label экране отобразится текст, введенный в TextField первой сцене.
  • После ввода текста во второй сцене TextField и щелчка по ней Button первая сцена Label обновляется, чтобы показать введенный текст.
Цукерберг рекомендует:  Android - Как заменить стандартную звонилку на Android

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

Сам код также прокомментирован с некоторыми деталями того, что происходит и как.

Main.java:

Controller1.java:

Controller2.java:

Layout1.fxml:

Layout2.fxml:

Автор: Zephyr Размещён: 26.06.2020 08:14

плюса

1 Репутация автора

Да, вы можете добавить в первый контроллер

затем во втором объявите клиента, а затем в нижней части вашего контроллера:

JavaFX несколько FXML и 1 общий контроллер

Я создал root FXML, который является BorderPane, и у него есть свой собственный корневой контроллер.
Я хочу динамично добавить FXML в центр этого borderpane.

Каждый из этих FXML совместно используют один и тот же контроллер, корневой контроллер. Я сделал это в netbeans, выбрав exsisting контроллер при создании пустой файл FXML.

Я также дал узлам разные имена идентификаторов, но корневой контроллер не распознает узлы в этих fxml.

Можно ли использовать один и тот же контроллер для разных FXML?

1 ответ

Фон

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

Даже если вы установите класс controller в каждом из загружаемых Вами fxml значений, он не будет совместно использовать один и тот же экземпляр controller, потому что каждый раз, когда вы загружаете контроллер, он будет создавать новый экземпляр (объект) класса controller (который, похоже, не является тем, что вы хотите).

потенциальное решение

Я не пробовал ни одного из этих решений, но считаю, что они будут работать.

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

О. вручную установите экземпляр контроллера.

    Удалите все ссылки на класс контроллера из файлов fxml.

Создайте экземпляр класса контроллера вручную.

Установите контроллер на свой экземпляр контроллера перед загрузкой каждого fxml.

Повторите шаг 3 для каждого из ваших файлов fxml, используя ту же ссылку контроллера каждый раз.

B. используйте фабрику регулятора.


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

Проблемы, связанные с двумя FXML файлов и контроллеров в JavaFX

У меня есть основной класс. Он находится в пакете «вид»

Он успешно загрузить файл start.fxml. Который также находится в пакете «вид».

Контроллер для этого start.fxml находится в пакете «контроллер».

В методе «начать» Я хочу, чтобы создать новую сцену, используя sample.fxml. Однако у меня были некоторые проблемы с ним. Например — java.lang.NullPointerException. Как я могу установить его?

NullPointerException В этом случае может быть потому , что структура JavaFX не в состоянии найти предоставляет .fxml файл. Вы должны предоставить полное имя, пример следующим образом :

Передача параметров JavaFX FXML

как я могу передать параметры во вторичное окно в javafx? Есть ли способ связаться с соответствующим контроллером?

например: Пользователь выбирает клиента из TableView и откроется новое окно с информацией о клиенте.

newStage будет новое окно. Проблема в том, что я не могу найти способ сообщить контроллеру, где искать информацию о клиенте (передавая идентификатор в качестве параметра).

8 ответов:

Рекомендуемый Подход

в этом ответе перечислены различные механизмы передачи параметров контроллерам FXML.

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

для больших, более сложных приложений, было бы целесообразно исследовать, если вы хотите использовать Инъекции Зависимостей или Автобусная Событие механизмы в вашем приложении.

передача параметров непосредственно от вызывающего абонента к контроллеру

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

что-то вроде следующего кода:

новый FXMLLoader построен как показано на рисунке пример кода, т. е. new FXMLLoader(location) . Расположение-это URL-адрес, и вы можете создать такой URL-адрес из ресурса FXML:

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

экземпляры FXMLLoader сами никогда ничего не знают об объектах домена. Вместо этого вы не передаете непосредственно объекты домена приложения в конструктор FXMLLoader ты:

  1. построить FXMLLoader на основе разметки fxml в указанном месте
  2. получить контроллер из экземпляра FXMLLoader.
  3. вызовите методы на извлеченном контроллере, чтобы предоставить контроллеру ссылки на объекты домена.

этот блог (другой писатель) предоставляет другой, но похожий, пример.

установка контроллера на FXMLLoader

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

чтобы установить контроллер на загрузчике (в JavaFX 2.x) вы также не можете определить a fx:controller атрибут в вашем fxml файл.

из-за ограничения на fx:controller определение в FXML, я лично предпочитаю получать контроллер от FXMLLoader, а не устанавливать контроллер в FXMLLoader.

имея контроллер получить параметры из внешнего статического метода

Использовать Инъекцию Зависимостей

FXMLLoader поддерживает системы впрыска зависимостей, такие как Guice, Spring или Java EE CDI, позволяя вам установить завод пользовательского контроллера на FXMLLoader. Это обеспечивает обратный вызов, который можно использовать для создания экземпляра контроллера с зависимыми значениями, введенными соответствующей системой внедрения зависимостей. Есть пример интеграции FXML-файл с весенним инъекции зависимостей система (к сожалению, ссылка мертва, и содержимое исчезло, если кто-нибудь знает о подобном примере, отредактируйте этот вопрос, чтобы ссылаться на него), хотя это немного неуклюже, чем при использовании новых функций фабрики пользовательских контроллеров, доступных в JavaFX 2.2.

действительно хороший, чистый подход к инъекции зависимостей иллюстрируется форсаже.база Форекс образец приложение air-hacks, который его использует. дожигатель.Форекс полагается на JEE6 javax.впрысните для выполнения инъекции зависимостей.

используйте шину событий

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

EventBus-это простой, но мощный API публикации / подписки с аннотациями, который позволяет POJOs чтобы общаться друг с другом в любом месте в JVM без необходимости ссылаться друг на друга.

последующие вопросы и ответы

на первом методе, почему вы возвращаете этап? Метод также может быть пустым, потому что вы уже даете команду show(); непосредственно перед этапом возврата;. Как вы планируете использование, возвращая этап

это функциональное решение проблемы. Этап возвращается из

javafx.сцена.Класс Node имеет пару методов setUserData(объект) и Объект getUserData()

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

Итак, вы можете позвонить на страницу.setUserData (info);

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


соблюдайте документацию здесь: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Перед фразой «в первой версии handleButtonAction () помечается с помощью @FXML, чтобы разрешить разметку, определенную в документе контроллера, чтобы вызвать его. Во втором примере поле кнопки аннотируется, чтобы позволить загрузчику установить его значение. Метод initialize() также Примеч.»

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

вот пример передачи параметров в документ fxml через пространство имен.

определить значение External Text для переменной пространства имен labelText :

это работает ..

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

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

в этом примере мы будем использовать 5 файлов:

  1. Главная.java — просто используется для запуска приложения и вызова первого контроллера.
  2. Controller1.java — контроллера для первый макет FXML.
  3. Controller2.java — контроллер для второго макета FXML.
  4. Layout1.FXML-файл — макет FXML для первой сцены.
  5. Layout2.FXML-файл — макет FXML для второй сцены.

все файлы перечислены в полном объеме в нижней части этого сообщения.

Цель: для демонстрации передачи значений от Controller1 до Controller2 и наоборот.

Программа:

  • первая сцена содержит TextField , a Button и Label . Когда Button щелкается, второе окно загружается и отображается, включая текст, введенный в TextField .
  • во второй сцене также есть TextField , a Button и Label . Элемент Label отображает текст, введенный в TextField на первом сцена.
  • при вводе текста во второй сцене TextField и нажав Button первая сцена Label обновляется для отображения введенного текста.

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

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

JavaFX — многие статические контроллеры FXML

A JavaFX приложение существует, и приложение запускается из файла Main.class , который extends Application :

Описание

Как вы можете видеть выше, у меня есть 3 FXMLControllers (один из них многократно используется [ extends StackPane ], другие нет). Я объявил все из них static, потому что хочу получить доступ к переменным из одного FXMLController от другого FXMLControllers . Я использую эту стратегию каждый раз, когда использую JavaFX , и я не думаю, что это хорошо.

Как я могу изменить код ниже, чтобы я мог обращаться к переменным или методам одного FXMLController из другого FXMLController ? Возможно ли это без использования ключевого слова static ?

Учтите, что контроллеры представлены из разных классов, которые могут быть в разных пакетах.

Также перед тем, как писать этот вопрос, я посмотрел Static @FXML-переменные в контроллере FXML

5 ответов

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

После долгого обсуждения я получил ссылку на этом сайте http://martinfowler.com/eaaDev/uiArchs.html, определяющий историческую эволюцию различных моделей, используемых в старости от Smalltalk до сих пор.

Фактическое решение использует Model Viewer Presenter Pattern(MVP) , который можно визуально описать с помощью этих изображений:

Для примера на JavaFX смотрите James_D ответ здесь (Применение MVC с JavaFx)

И последнее, но не менее важное: посмотрите здесь:

Наконец:

Если что-то неточно, не стесняйтесь редактировать.

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

Если вы хотите попробовать JRebirth, просто сократите свое приложение на 4 части:

  • MainModel состоит из:
    • MainSceneModel
    • CaptureWindowModel
    • SettingsModel

Вы можете получить доступ к одному от кого-либо с помощью getModel (Model.class) или отправить асинхронное сообщение с помощью sendWave (Wave).

MainModel может использовать innerComponent для плотной привязки детской модели к ней.

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

Вы можете реализовать свой собственный контроллер factory, чтобы вы могли создать свой собственный контекст контроллеров.

Я использовал spring с javaFX, и я использовал свои собственные контроллеры factory с помощью spring, таким образом вы можете вводить один контроллер в другой (вам не нужно, поскольку эти подключения должны быть включены модель)


JavaFx в основном состоит из набора [хорошо разработанных] инструментов, но, к сожалению, сама по себе не обеспечивает хорошую структуру для создания сложных дизайнов пользовательского интерфейса, например. MVC/MVP, просматривать потоки и действия на нескольких контроллерах. Поэтому вам нужно полагаться на сторонние рамки приложений для таких, например:

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

Цукерберг рекомендует:  Разбираем Underscore.js по косточкам. Метод filter

Пример использования DataFx

DataFx использует концепцию под названием Flow для сопоставления представлений, совместно использующих поток событий (и, возможно, данных) между собой. Используя Flow в сочетании с EventSystem, вы можете определить и получить доступ к методам на других контроллерах и назначить пользовательские прослушиватели событий различным событиям, связанным с узлами JavaFx, в разные контроллеры, разделяющие поток.

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

code .makery

Learning how to code.

Статьи в этой серии

Скачать исходники

Языки

Часть 3: Взаимодействие с пользователем

Часть 3: Содержание

  • Реакция на выбор адресатов в таблице.
  • Добавление функциональности кнопкам add, edit и remove.
  • Создание диалогового окна для изменения информации об адресатах.
  • Проверка пользовательского ввода.

Реакция на выбор адресатов в таблице

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

Сначала давайте добавим новый метод в класс PersonOverviewController . Он поможет нам заполнять текстовые метки данными указанного адресата ( Person ).

Создайте метод showPersonDetails(Person person) . Его код проходится по меткам, и, используя метод setText(. ) , присваивает им соответствующие значения, взятые из переданного в параметре объекта Person. Если в качестве параметра передаётся null , то весь текст в метках будет очищен.

PersonOverviewController.java

Преобразование дня рождения в строку

Обратите внимание, что мы просто так не можем присвоить текстовой метке значение поля birthday , так как тип его значения LocalDate а не String . Для того чтобы это сделать, нам надо сначала отформатировать дату.

Мы будем преобразовывать тип LocalDate в тип String и обратно в нескольких местах программы, поэтому, хорошей практикой считается создание для этой цели вспомогательного класса, содержащего статические методы. Этот вспомогательный класс мы назовем DateUtil и разместим его в новом пакете ch.makery.address.util :

DateUtil.java

Использование класса DateUtil

Теперь мы можем использовать наш новый класс DateUtil в методе showPersonDetails класса PersonOverviewController . Замените комментарий TODO следующей строкой:

Наблюдение за выбором адресатов в таблице

Чтобы знать о том, что пользователь выбрал определённую запись в таблице, нам необходимо прослушивать изменения.

Для этого в JavaFX существует интерфейс ChangeListener с единственным методом changed(. ) . Этот метод имеет три параметра: observable , oldValue и newValue .

Мы будем реализовывать интерфейс ChangeListener с помощью лямбда-выражений из Java 8. Давайте добавим несколько строчек кода к методу initialize() класса PersonOverviewController . Теперь этот метод выглядит так:

PersonOverviewController.java

Если мы передаём в параметр метода showPersonDetails(. ) значение null , то все значения меток будут стёрты.

В строке personTable.getSelectionModel. мы получаем selectedItemProperty таблицы и добавляем к нему слушателя. Когда пользователь выбирает запись в таблице, выполняется наше лямбда-выражение. Мы берём только что выбранную запись и передаём её в метод showPersonDetails(. ) .

Запустите свое приложение и проверьте, отображаются ли детали адресата в правой части, когда в таблице выбирается определённый адресат.

Если у вас что-то не работает, то вы можете сравнить свой класс PersonOverviewController с PersonOverviewController.java.

Кнопка Delete

В нашем пользовательским интерфейсе есть кнопка Delete, но пока она не работает. В приложении Scene Builder мы можем задать действие, которое будет выполняться при нажатии на эту кнопку. Любой метод внутри класса-контроллера, помеченный аннотацией @FXML (или публичный), доступен Scene Builder. Поэтому, давайте сперва добавим в конец класса PersonOverviewController метод удаления адресата, а уже потом назначим его обработчиком кнопки Delete.

PersonOverviewController.java

Теперь в приложении Scene Builder откройте файл PersonOverview.fxml . Выберите кнопку Delete, откройте вкладку Code и укажите метод handleDeletePerson в значение пункта On Action.

Обработка ошибок


Если вы сейчас запустите приложение, то уже сможете удалять выбранных адресатов из таблицы. Но что произойдёт, если не будет выбран ни один адресат, а вы нажмёте кнопку Delete,?

Вылетит исключение ArrayIndexOutOfBoundsException , потому что не получится удалить адресата с индексом -1 . Значение -1 возвращается методом getSelectedIndex() , когда в таблице ничего не выделено.

Естественно, игнорировать эту ошибку будет некрасиво. Мы должны сообщать пользователю о том, что он, перед тем как нажимать кнопку Delete, должен выбрать запись в таблице. (Ещё лучше совсем деактивировать кнопку, чтобы у пользователя не было соблазна сделать что-то не так).

Добавим в метод handleDeletePerson некоторые изменения. Теперь, когда пользователь нажимает на кнопку Delete, а в таблице ничего не выбрано, он увидит простое диалоговое окно:

PersonOverviewController.java

Диалоги создания и изменения адресатов

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

Дизайн окна редактирования

  1. Внутри пакета view создайте новый fxml-файл PersonEditDialog .
  2. Используйте компоненты GridPane , Label , TextField и Button для создания окна редактирования, похожего на это:

Если что-то не работает, вы можете скачать PersonEditDialog.fxml.

Создание контроллера

Создайте класс-контроллер для нового окна — PersonEditDialogController.java :

PersonEditDialogController.java

Кое-какие заметки по поводу этого контроллера:

  • Для указания адресата, данные которого должны быть изменены, метод setPerson(. ) может быть вызван из другого класса;
  • Когда пользователь нажимает на кнопку ОК, то вызывается метод handleOK() . Первым делом данные, введённые пользователем, проверяются в методе isInputValid() . Если проверка прошла успешно, то объект адресата заполняется данными, которые ввёл пользователь. Эти изменения будут напрямую применяться к объекту адресата, который был передан в качестве аргумента метода setPerson(. ) !
  • Логическая переменная okClicked служит для определения того, какую из двух кнопок, ОК или Cancel нажал пользователь.

Привязка класса-контроллера к fxml-файлу

Теперь мы должны связать наш класс-контроллер с fxml-файлом. Для этого выполните следующие действия:

  1. Откройте файл PersonEditDialog.fxml в Scene Builder;
  2. С левой стороны во вкладке Controller установите наш класс PersonEditDialogController в качестве значения параметра Сontroller Сlass;
  3. Установите соответствующие значения fx:id для всех компонентов TextField ;
  4. В значениях параметров onAction для наших кнопок укажите соответствующие методы-обработчики.

Вызов диалога редактирования

Добавьте в класс MainApp метод для загрузки и отображения диалога редактирования записей:

MainApp.java

Добавьте следующие методы в класс PersonOverviewController . Когда пользователь будет нажимать на кнопки New. или Edit. , эти методы будут обращаться к методу showPersonEditDialog(. ) в классе MainApp .

PersonOverviewController.java

В приложении Scene Builder откройте представление PersonOverview.fxml и для кнопок New. и Edit. задайте соответствующие методы-обработчики в параметре On Action .

Готово!

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

Я надеюсь, что идея и структура данного приложения поможет вам начать писать свои собственные приложения JavaFX! Удачи.

Что дальше?

В 4-й части учебника мы будем подключать к нашему приложению CSS-стили.

JavaFX FXML Controller Example

Posted by: Andreas Pomarolli in FXML April 7th, 2020 0 Views

This is a JavaFX FXML Controller Example. FXML is an XML-based language designed to build the user interface for JavaFX applications. You can use FXML to build an entire Scene or part of a Scene . FXML allows application developers to separate the logic for building the UI from the business logic. If the UI part of the application changes, you do not need to recompile the JavaFX code. Instead you can change the FXML using a text editor and rerun the application. You still use JavaFX to write business logic using the Java language. An FXML document is an XML document.

A JavaFX scene graph is a hierarchical structure of Java objects. XML format is well suited for storing information representing some kind of hierarchy. Therefore, using FXML to store the scene-graph is very intuitive. It is common to use FXML to build a scene graph in a JavaFX application.

Table Of Contents

The following examples uses Java SE 7 and JavaFX 2.2.

1. Introduction to FXML

1.1 The FXML Code

1.2 Adding UI Elements


The root element of the FXML document is the top-level object in the object-graph. The top-level object of the above example is a VBox. Therefore, the root element of your FXML would be:

How do you know that to represent a VBox in the object-graph, you need to use a tag in FXML? It is both difficult and easy. It is difficult because there is no documentation for FXML tags. It is easy because FXML has a few rules explaining what constitutes a tag name. For example, if a tag name is the simple or fullqualified name of a class, the tag will create an object of that class. The above element will create an object of the VBox class. The above FXML can be rewritten using the fully qualified class name:

In JavaFX, layout panes have children. In FXML, layout panes have children as their child elements. You can add a Label and a Button and other elements to the VBox as follows:

This defines the basic structure of the object-graph for our application. It will create a VBox with two labels, a TextField, a TextArea and a Button .

1.3 Importing Java Types in FXML

To use the simple names of Java classes in FXML, you must import the classes as you do in Java programs. There is one exception. In Java programs, you do not need to import classes from the java.lang package . However, in FXML, you need to import classes from all packages, including the java.lang package . An import processing instruction is used to import a class or all classes from a package. The following processing instructions import the VBox , Label , and Button classes:

The following import processing instructions import all classes from the javafx.scene.control and java.lang packages:

1.4 Setting Properties in FXML

You can set properties for Java objects in FXML. A property for an object can be set in FXML if the property declaration follows the JavaBean conventions. The attribute name or the property element name is the same as the name of the property being set. The following FXML creates a TextField and sets its prefWidth property using an attribute:

1.5 Specifying FXML Namespace

FXML does not have an XML schema. It uses a namespace that needs to be specified using the namespace prefix “fx”. For the most part, the FXML parser will figure out the tag names such as tag names that are classes, properties of the classes, and so on. FXML uses special elements and attribute names, which must be qualified with the “fx” namespace prefix. Optionally, you can append the version of the FXML in the namespace URI. The FXML parser will verify that it can parse the specified.

The following FXML declares the “fx” namespace prefix.

1.6 Assigning an Identifier to an Object

An object created in FXML can be referred to somewhere else in the same document. It is common to get the reference of UI objects created in FXML inside the JavaFX code. You can achieve this by first identifying the objects in FXML with an fx:id attribute. The value of the fx:id attribute is the identifier for the object. If the object type has an id property, the value will be also set for the property. Note that each Node in JavaFX has an id property that can be used to refer to them in CSS. The following is an example of specifying the fx:id attribute for a Label .

1.7 The Corresponding Java Class

An FXML document defines the view part (the GUI) of a JavaFX application. You need to load the FXML document to get the object-graph it represents. Loading an FXML is performed by an instance of the FXMLLoader class. The FXMLLoader class provides several constructors that let you specify the location, charset, resource bundle, and other elements to be used for loading the document. FXMLLoader supports loading a FXML document using an InputStream. The following snippet of code loads the same FXML document using an InputStream .

Цукерберг рекомендует:  Htmlcss - С чего начать начинающему верстальщику

Internally, the FXMLLoader reads the document using streams, which may throw an IOException. All versions of the load() method in FXMLLoader class throw IOException . In your application, you will need to handle the exception. The FXMLLoader class contains several versions of the load() method. Some of them are instance methods and some static methods. You need to create an FXMLLoader instance and use the instance load() method, if you want to retrieve more information from the loader, such as the controller reference, resource bundle, the location, charset, and root object.

What do you do next after loading an FXML document? The loader returns a VBox , which is set as the root for the Scene . The rest of the code is the same as you have been using except for one difference in the declaration of the start() method. The method declares that it may throw an IOException , which you had to add because you have called the load() method of the FXMLLoader inside the method.

1.8 The GUI

The following mage shows the application after starting. But at this time, a click on the OK-Button has no effect. The reason for this behaviour is the fact, that we have not defined an EventHandler at this time.

A simple JavaFX FXML Example

2. Using Script Event Handlers

2.1 The FXML Code

You can set event handlers for nodes in FXML. Setting an event handler is similar to setting any other properties. In FXML, you can specify two types of event handlers:

  • Script Event Handlers
  • Controller Event Handlers

In this chapter we will discuss Script Event Handlers. The Controller Event Handlers will be discussed in the following chapter.

The script event handler is used when the event handler is defined in a scripting language. The value of the attribute is the script itself, such as a function call or one or more statements. The following snippet of FXML sets the ActionEvent handler for a Button that calls the printOutput() function defined using JavaScript.

If you want to execute the function printOutput() when the Button is clicked, you can set the event handler as:

2.2 The Corresponding Java Class

2.3 The GUI

The following image shows the result of our program after inserting a Text in the TextField and pressing the Button “OK”:

A JavaFX FXML Example with a JavaScript Event Handler

3. Using Controller Event Handlers

3.1 The FXML Code

A controller is simply a class name whose object is created by FXML and used to initialize the UI elements. FXML lets you specify a controller on the root element using the fx:controller attribute. Note that only one controller is allowed per FXML document, and if specified, it must be specified on the root element. The following FXML specifies a controller for the VBox element.

A controller needs to conform to some rules and it can be used for different reasons:

  • The controller is instantiated by the FXML loader.
  • The controller must have a public no-args constructor. If it does not exist, the FXML loader will not be able to instantiate it, which will throw an exception at the load time.
  • The controller can have accessible methods, which can be specified as event handlers in FXML.
  • The FXML loader will automatically look for accessible instance variables of the controller. If the name of an accessible instance variable matches the fx:id attribute of an element, the object reference from FXML is automatically copied into the controller instance variable. This feature makes the references of UI elements in FXML available to the controller. The controller can use them later, such as binding them to model.
  • The controller can have an accessible initialize() method, which should take no arguments and have a return type of void. The FXML loader will call the initialize() method after the loading of the FXML document is complete.

3.2 The Controller Class

The controller class uses a @FXML annotation on some members. The @FXML annotation can be used on fields and methods. It cannot be used on classes and constructors. By using a @FXML annotation on a member, you are declaring that the FXML loader can access the member even if it is private. A public member used by the FXML loader does not need to be annotated with @FXML . However, annotating a public member with @FXML is not an error. It is better to annotate all members, public and private, used by the FXML loader with the @FXML annotation. This tells the reader of your code how the members are being used.

The following FXML sets the printOutput() method of the controller class as the event handler for the Button :

There are two special instance variables that can be declared in the controller and they are automatically injected by the FXML loader:


  • @FXML private URL location;
  • @FXML private ResourceBundle resources;

The location is the location of the FXML document. The resources is the reference of the ResourceBundle. When the event handler attribute value starts with a hash symbol (#), it indicates to the FXML loader that printOutput() is the method in the controller, not in a script.

The event handler method in the controller should conform to some rules:

  • The method may take no arguments or a single argument. If it takes an argument, the argument type must be a type assignment compatible with the event it is supposed to handle.
  • Conventionally, the method return type should be void, because there is no taker of the returned value.
  • The method must be accessible to the FXML loader: make it public or annotate it with @FXML.
  • When the FXML loader is done loading the FXML document, it calls the initialize() method of the controller. The method should not take any argument. It should be accessible to the FXML loader. In the controller, you used the @FXML annotation to make it accessible to the FXML loader.

3.3 The Corresponding Java Class

3.4 The GUI

The following image shows the result of our program:

A JavaFX FXML Controller Example

4. Download Java Source Code

This was an example JavaFX FXML Controller Example.

Как вызвать функции на этапе в файле контроллера JavaFX

Я использую javafx вдоль с fxml, поэтому я использую контроллер для реального кодирования. Мне нужно сделать несколько операций на сцене, например, получить положение по оси x или y. Я пробовал stage.getX() и stage.getY , но они не работают (название сцены с высокой степенью важности является ошибкой). Как использовать такие функции в моем контроллере? Я попытался сделать это в своем основном файле:

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

Я знаю, что «этап» отсутствует. Но как получить «этап» в моем контроллере?

javafx javafx-2 location fxml

6 ответов

25 Решение tarrsalah [2013-05-20 19:47:00]

С панели root в файле fxml :

Вы можете получить сцену из нее:

У вас есть ссылка на ваш этап, вы можете делать то, что хотите.

14 jewelsea [2013-05-20 20:47:00]

Пример решения

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

Вот пример программы, которая создает окно утилиты, которое отслеживает координаты x и y экрана при перетаскивании окна утилиты. Содержимое окна утилиты отображается в определенной области fxml.

Альтернативные решения

Ответ tarrsalah просто на этапе создания компонента @FXML также является хорошим способом, если вы знаете, что корневой компонент контроллера уже добавлен в сцену, которая уже добавлена ​​на сцену (что часто является случай, когда что-то вроде обработчика событий кнопки запускается).

Другой способ сделать это похож на ответ tarrsalah, но использовать ChangeListeners в свойстве сцены для @FXML node и свойства окна измененной сцены. Это позволяет отслеживать изменения сцены и сцены в случае перемещения панели на новую сцену или сцену. В большинстве случаев вам не нужно отслеживать эти изменения, так как большинство панелей просто добавляются в одну сцену, которая остается на одном этапе.

Ответы на дополнительные вопросы и комментарии

Могу ли я получить более простой ответ?

tarrsalah уже предоставил более простой ответ.

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

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

Не используйте FXML, когда вы начинаете разрабатывать свои первые приложения Java и JavaFX. Вместо этого просто придерживайтесь стандартного Java API в вашем коде JavaFX, для которого есть еще много tutorials, а также отличный Образец ансамбля для ссылки.

Перед началом JavaFX убедитесь, что вы завершили все Учебные тропы Java, освещающие основы. Для начала использования JavaFX требуется только основы Java, вам не нужно вникать в изучение Java Enterprise Edition и забыть о Swing.

Рассмотрите возможность использования SceneBuilder и FXML для более крупных приложений, как только вы написали несколько базовых приложений JavaFX, с ручной кодировкой некоторых макетов в соответствии с Java API и достигли уровня комфорта с использованием основных технологий. В то время вы, скорее всего, обнаружите, что обучение FXML довольно простое. Атрибуты и элементы FXML — это просто отражение API Java.

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

Я не могу этого сделать, так как не знаю, что для вас необычно.

Если для каждой сложной концепции есть определенные части кода, которые вы не можете понять своими собственными знаниями или исследованиями, создайте новый вопрос StackOverflow.

Ну, самый простой ответ на этот вопрос.

В своем основном классе создайте экземпляр (объект) вашего класса контроллера:

В вашем классе Controller вы должны поместить метод «извлечения» (сеттер):

И затем вы можете добавить полноэкранную кнопку;)

1 Paul [2015-09-17 01:21:00]

Эта ветка устарела, но я обнаружил что-то подходящее для нее совершенно случайно. Я думал, что это ошибка кодирования, которая не должна была работать, но это было так. В классе контроллера просто объявляем следующую переменную-член:

@FXML частная стадия этапа;

предоставил мне доступ к этапу контроллера, так же как и доступ к виджету в документе fxml. Я не нашел никакой документации, что это так, но я признаю, что я нооб для JavaFX (хотя старая рука у Swing). Но, похоже, это работает. Может быть, опасно рассчитывать на это?

С *.FXML файлами и контроллерами и не с Main или Events, используйте это:

может быть любым элементом управления или элементом в FXML, в моем случае это AnchorPane:

Лучший подход — создать новый контроллер и передать stage через конструктор (не использовать fx:controller в файле FXML), в противном случае stage будет null при вызове initialize() (В тот момент времени, когда load() вызывает initialize() , к scene присоединяется stage , поэтому scene stage — null ).

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