В октябре 2011 года я использовал статью Hello JavaFX 2.0: Введение в бета-версию среды IDE NetBeans 7.1, чтобы рассмотреть использование бета- версии NetBeans IDE 7.1 для создания простого приложения JavaFX 2.0 в стиле Hello, World . В этой статье я расскажу об использовании среды IDE NetBeans 7.1 ( больше не в бета-версии ) для создания немного более сложного приложения JavaFX 2, которое интенсивно использует FXML .
В большинстве моих постов о JavaFX 2 до этого момента подчеркивалась «чистая Java» природа JavaFX 2. Примеры в этих постах были написаны на стандартной Java с использованием API JavaFX 2 непосредственно из исходного кода Java. Эти примеры также были собраны с помощью компилятора javac и выполнены с помощью средства запуска приложений java . В этой статье я возьму один из этих примеров [ (Pure Java) JavaFX 2.0 Menus ] и » перенес » его для использования FXML для макета презентации.
Для удобства я включил полный список Java для реализации «чистого Java» меню JavaFX 2.
Демонстрация меню JavaFX 2.0 (Pure Java)
package dustin.examples; import static java.lang.System.out; import javafx.application.Application; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; import javafx.scene.paint.Color; import javafx.stage.Stage; /** * Example of creating menus in JavaFX. * * @author Dustin */ public class JavaFxMenus extends Application { /** * Build menu bar with included menus for this demonstration. * * @param menuWidthProperty Width to be bound to menu bar width. * @return Menu Bar with menus included. */ private MenuBar buildMenuBarWithMenus(final ReadOnlyDoubleProperty menuWidthProperty) { final MenuBar menuBar = new MenuBar(); // Prepare left-most 'File' drop-down menu final Menu fileMenu = new Menu("File"); fileMenu.getItems().add(new MenuItem("New")); fileMenu.getItems().add(new MenuItem("Open")); fileMenu.getItems().add(new MenuItem("Save")); fileMenu.getItems().add(new MenuItem("Save As")); fileMenu.getItems().add(new SeparatorMenuItem()); fileMenu.getItems().add(new MenuItem("Exit")); menuBar.getMenus().add(fileMenu); // Prepare 'Examples' drop-down menu final Menu examplesMenu = new Menu("JavaFX 2.0 Examples"); examplesMenu.getItems().add(new MenuItem("Text Example")); examplesMenu.getItems().add(new MenuItem("Objects Example")); examplesMenu.getItems().add(new MenuItem("Animation Example")); menuBar.getMenus().add(examplesMenu); // Prepare 'Help' drop-down menu final Menu helpMenu = new Menu("Help"); final MenuItem searchMenuItem = new MenuItem("Search"); searchMenuItem.setDisable(true); helpMenu.getItems().add(searchMenuItem); final MenuItem onlineManualMenuItem = new MenuItem("Online Manual"); onlineManualMenuItem.setVisible(false); helpMenu.getItems().add(onlineManualMenuItem); helpMenu.getItems().add(new SeparatorMenuItem()); final MenuItem aboutMenuItem = MenuItemBuilder.create() .text("About") .onAction( new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { out.println("You clicked on About!"); } }) .accelerator( new KeyCodeCombination( KeyCode.A, KeyCombination.CONTROL_DOWN)) .build(); helpMenu.getItems().add(aboutMenuItem); menuBar.getMenus().add(helpMenu); // bind width of menu bar to width of associated stage menuBar.prefWidthProperty().bind(menuWidthProperty); return menuBar; } /** * Start of JavaFX application demonstrating menu support. * * @param stage Primary stage. */ @Override public void start(final Stage stage) { stage.setTitle("Creating Menus with JavaFX 2.0"); final Group rootGroup = new Group(); final Scene scene = new Scene(rootGroup, 800, 400, Color.WHEAT); final MenuBar menuBar = buildMenuBarWithMenus(stage.widthProperty()); rootGroup.getChildren().add(menuBar); stage.setScene(scene); stage.show(); } /** * Main executable function for running examples. * * @param arguments Command-line arguments: none expected. */ public static void main(final String[] arguments) { Application.launch(arguments); } }
Помимо добавления возможности писать приложения JavaFX на «чистой Java», как это реализовано в последнем листинге кода, JavaFX 2 также предоставляет FXML , грамматику XML для указания макета приложения JavaFX. Такой подход очень похож, обеспечиваемой Flex «s MXML , по OpenLaszlo » s LZX , и Mozilla «s XUL . Этот подход хорошо работает с иерархическим графом сцен JavaFX.
Портированный код FXML показан ниже. Легко увидеть структуру представления в этом XML.
JavaFx2Menus.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox id="vbox" prefHeight="400" prefWidth="800" xmlns:fx="http://javafx.com/fxml" fx:controller="dustin.examples.MenuController"> <MenuBar fx:id="menuBar" onKeyPressed="#handleKeyInput"> <menus> <Menu text="File"> <items> <MenuItem text="New"/> <MenuItem text="Open"/> <MenuItem text="Save"/> <MenuItem text="Save As"/> <SeparatorMenuItem /> <MenuItem text="Exit"/> </items> </Menu> <Menu text="JavaFX 2.0 Examples"> <items> <MenuItem text="Text Example"/> <MenuItem text="Objects Example"/> <MenuItem text="Animation Example"/> </items> </Menu> <Menu text="Help"> <items> <MenuItem text="Search" disable="true"/> <MenuItem text="Online Manual" visible="false"/> <SeparatorMenuItem /> <MenuItem text="About" onAction="#handleAboutAction"/> </items> </Menu> </menus> </MenuBar> </VBox>
Важную часть этого простого FXML можно просмотреть на одной странице в среде IDE NetBeans 7.1, как показано на следующем снимке экрана.
Помимо краткости FXML и эстетически привлекательного иерархического представления, FXML также должен выглядеть знакомым для всех, кто работал с Flex, OpenLaszlo или XUL. Большая часть структуры презентации легко идентифицируется в документе FXML. Этот пример включает в себя обработчик onAction, который отвечает на пункт меню «О программе», и с панелью меню также связано действие onKeyPressed (я не смог найти способ легко связать этот обработчик с самим элементом меню). Оба эти действия ссылаются на имена, которые начинаются с символа #. Имена, следующие за #, являются именами методов в классе контроллера (определяется атрибутом fx: controller в VBox как класс с именем dustin.examples.MenuController). Источник для этого класса контроллера показан ниже.
MenuController.java
package dustin.examples; import static java.lang.System.out; import java.net.URL; import java.util.ResourceBundle; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.MenuBar; import javafx.scene.input.InputEvent; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; /** * Controller class for JavaFX 2 Menus with FXML post and demonstration. * * @author Dustin */ public class MenuController implements Initializable { @FXML private MenuBar menuBar; /** * Handle action related to "About" menu item. * * @param event Event on "About" menu item. */ @FXML private void handleAboutAction(final ActionEvent event) { provideAboutFunctionality(); } /** * Handle action related to input (in this case specifically only responds to * keyboard event CTRL-A). * * @param event Input event. */ @FXML private void handleKeyInput(final InputEvent event) { if (event instanceof KeyEvent) { final KeyEvent keyEvent = (KeyEvent) event; if (keyEvent.isControlDown() && keyEvent.getCode() == KeyCode.A) { provideAboutFunctionality(); } } } /** * Perform functionality associated with "About" menu selection or CTRL-A. */ private void provideAboutFunctionality() { out.println("You clicked on About!"); } @Override public void initialize(final URL url, final ResourceBundle rb) { menuBar.setFocusTraversable(true); } }
Приведенный выше код из класса контроллера включает в себя два метода, на которые ссылаются как на обработчики действий в FXML с префиксами #. Эти два метода являются закрытыми и обычно не будут видны загрузчику FXML, но использование аннотации @FXML решает эту проблему. Атрибут menuBar также является закрытым, но видимым для загрузчика FXML благодаря собственной аннотации @FXML.
Чтобы приложение отвечало на CTRL-A перед любым начальным доступом к строке меню, я обнаружил, что мне нужно иметь ссылку на строку меню в контроллере и вызвать setFocusTraversable (true) для этого экземпляра. Без этого CTRL-A будет отвечать только в том случае, если я впервые нажму на строку меню один раз. Крюком от FXML к этому атрибуту в контроллере является атрибут fx: id, используемый в FXML. Этот атрибут ссылается на имя «menuBar», которое (не случайно) также является именем атрибута в классе контроллера. Другими словами, атрибут fx: id = «menuBar» связывает элемент XML, который включен в FXML, с атрибутом с тем же именем в контроллере.
В этом посте я не показывал многое, касающееся среды IDE NetBeans 7.1, но стоит отметить, что у меня были все соответствующие файлы, созданные в новом проекте с использованием мастера создания проектов NetBeans IDE 7.1 и выбора приложения JavaFX FXML в качестве типа проекта. , Это создало основной файл FXML, основной файл контроллера и основной класс для загрузки FXML и запуска приложения. Я изменил их в приведенных выше примерах для FXML и для класса контроллера. Модифицированный класс, который загружает FXML и запускает приложение JavaFX, показан ниже. (Там не так много!)
JavaFxMenusWithFxmlDemo.java
package dustin.examples; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; /** * Simple example of JavaFX 2 FXML used to demonstrate JavaFX 2 menus. This is a * "port" of the example featured using "pure Java" (no FXML) in the post * "(Pure Java) JavaFX 2.0 Menus" * (http://marxsoftware.blogspot.com/2011/12/pure-java-javafx-20-menus.html). * * @author Dustin */ public class JavaFxMenusWithFxmlDemo extends Application { /** * Main function for running this application. * * @param arguments Command-line arguments: none expected. */ public static void main(String[] arguments) { Application.launch(JavaFxMenusWithFxmlDemo.class, arguments); } /** * Overridden Application.start(Stage) method. * * @param stage Primary stage. * @throws Exception JavaFX application exception. */ @Override public void start(final Stage stage) throws Exception { final Parent fxmlRoot = FXMLLoader.load(getClass().getResource("JavaFx2Menus.fxml")); stage.setScene(new Scene(fxmlRoot)); stage.show(); } }
Я не буду показывать здесь вывод, потому что это по сути то, что произвела версия «чистой Java», которая показана в моем посте об этом подходе. Помимо создания файлов, которые я адаптировал для своего приложения, мастер новых проектов NetBeans IDE 7.1 для приложения JavaFX FXML также создал проект, который автоматически упаковывает то, что мне нужно для приложения JavaFX, в исполняемый файл JAR. Содержимое JAR в этом случае показано на следующем снимке экрана.
Самая хитрая часть об использовании FXML — это относительно менее доступная документация. Чистые API Java имеют сильную документацию Javadoc API , но я не знаю ничего подобного для FXML (включая документацию или схему для пространства имен http://javafx.com/fxml ). Есть несколько замечательных ресурсов FXML, таких как Начало работы с FXML и Введение в FXML . Возможно, лучшим документом для выяснения того, какие элементы и атрибуты предоставляет FXML, является Представление FXML: Язык разметки для JavaFX , который объясняет «отображение» стандартных классов Java API JavaFX на элементы и атрибуты JavaFX FXML.
FXML представляется довольно привлекательным подходом для создания приложения JavaFX, поскольку он хорошо отделяет представление (FXML) от бизнес-логики (класса контроллера и классов, которые будут вызываться методами контроллера). Это может упростить визуальное представление макета графического интерфейса в иерархическом XML-коде и не допустить беспорядка в логике и представлении.
От http://marxsoftware.blogspot.com/2012/01/focus-on-javafx-2-fxml-with-netbeans-71.html