В октябре 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

