5.7.4 FXML

有些JavaFX程序的界面比较复杂,包含非常多的元素。创建这类界面的代码非常繁琐,可读性差,也很难进行维护。JavaFX允许开发人员使用FXML语言来描述程序的界面。FXML使用的是XML的语法。可以从FXML文档中创建出用户界面。使用FXML的好处是界面上组件之间的层次结构非常清晰,易于更新和维护。不熟悉Java的界面设计人员也可以用FXML来描述界面。

在JavaFX程序中,使用FXML有三个步骤。第一步是使用FXML的语法格式来描述程序的用户界面;第二步是通过javafx.fxml.FXMLLoader类加载一个FXML文档,并得到相应的用户界面的对象;第三步是在JavaFX程序中直接使用得到的组件对象。

FXML的基本语法比较简单。FXML中的元素可以表示对象实例、属性或代码块。对于对象实例,元素的名称是对应的Java类的名称,而元素的属性用来设置对象的属性值。对象的某些属性比较复杂,不能用简单的XML属性来描述,只能用子元素来表示。代码清单5-20给出了一个用FXML描述JavaFX程序界面的示例。处理指令“import”类似Java中的import语句。FXML文档中的元素“<VBox>”、“<HBox>”、“<Button>”和“<Label>”等用来创建对应的对象。简单的属性,如VBox类的spacing,可以直接在XML元素的属性上设置;复杂的属性,如VBox类的对象所包含的子组件children,可以通过子元素来设置。

代码清单5-20 使用FXML描述JavaFX程序界面的示例


<?xml version="1.0"encoding="UTF-8"?>

<?import java.lang.*?>

<?import javafx.scene.*?>

<?import javafx.collections.*?>

<?import javafx.scene.control.*?>

<?import javafx.scene.layout.*?>

<VBox id="main"spacing="20"prefHeight="300"prefWidth="400"xmlns:fx="http://javafx.com/fxml"fx:controller="javafx.fxml.Form">

<children>

<HBox spacing="10">

<children>

<Label text="Name:"/>

<TextField fx:id="name"promptText="Enter your name"/>

</children>

</HBox>

<HBox spacing="10">

<children>

<Label text="Gender:"/>

<ListView fx:id="gender">

<items>

<FXCollections fx:factory="observableArrayList">

<String fx:value="Male"/>

<String fx:value="Female"/>

</FXCollections>

</items>

</ListView>

</children>

</HBox>

<HBox>

<children>

<Button id="button"text="Say"onAction="#say"fx:id="button"/>

<Label id="message"fx:id="message"/>

</children>

</HBox>

</children>

</VBox>


每个FXML文档可以与一个Java对象关联起来,这个Java对象被称为FXML文档的控制器。通过FXML文档根元素的“fx:controller”属性来声明控制器的Java类名。在FXML文档中可以引用控制器对象中的方法。具体的格式是在方法名称上加上“#”作为前缀。代码清单5-20中的“<Button>”元素的“onAction”属性引用了控制器对象中的“say”方法。

创建出FXML文档之后,可以在JavaFX程序中通过FXMLLoader类来使用它。代码清单5-21给出了相关的示例。FXMLLoader类的load方法可以从不同的来源加载FXML文档,并创建出FXML文档中声明的组件对象。这个创建出来的组件对象可以在JavaFX程序中自由使用。

代码清单5-21 在JavaFX程序中加载FXML文档的示例


public class JavafxFxml extends Application{

public static void main(String[]args){

launch(args);

}

public void start(Stage stage)throws Exception{

Parent root=FXMLLoader.load(getClass().getResource("Form.fxml"));

stage.setScene(new Scene(root));

stage.show();

}

}