1 FXML入门教程
本部分教程包括两部分内容:
1、为什么使用FXML(基本介绍以及用FXML创建用户界面的好处);
2、使用FXML创建用户界面(通过创建简单登录应用来完成本教程部分)。
1.1 为何使用FXML
FXML是基于XML的语言,它提供与应用逻辑代码分离的构建用户界面的结构。展现层和应用逻辑的分离对web开发者更有吸引力:因为他们可以利用java组件组装用户界面而不需要掌握获取并填充数据的代码。
接下的部分提供更多关于FXML的信息,之后你会选择FXML创建用户界面而不是其它方法。下面分三部分介绍FXML
l FXML介绍;
l FXML简单示例;
l FXML好处。
1.1.1 FXML介绍
FXML没有相应的模式,但有一个基本的预定义结构。用FXML表达什么,如何用它构建场景图,依赖于你构造对象的API。因为FXML直接映射到Java,参照API文档以更好地什么理解元素和属性允许应用。通常,大多数JavaFX类能作为元素使用,大多数Bean的Properties特性可以用作属性。
来源于模型-视图-控制器(MVC)观点,FXML文件包含用户界面描述的部分称之为视图。控制器是可选性实现Initializable类的Java类,这被声明为FXML文件的控制器。模型由定义java端的域对象构成,并通过控制器连接到视图。在“使用FXML创建用户界面”中有一个结构性示例。
使用FXML创建用户界面时,对大而复杂的布景、表单、数据实体或是复杂动画,使用FXML是特别有用的。FXML也是适合定义静态布局结构,诸如表单、控件和表等。另外,通过包含脚本还能使用FXML构建动态布局。
1.1.2 FXML简单示例
最简单展示FXML好处的方法是实例。如图1-1所示,它展示了一个包含Pane布局的用户界面,Pane布局有一个顶部和中部区域,每个区域中包含一个label标签。
图1-1 边格简单示例
说明:布局类BorderPane定义两个区域:顶部区域和中部区域。顶部区域包含一个“Page Title”标签,中部区域包含一个“some data here”标签。
首先,看下用户界面结构如何,在源代码中如何直接创建,如下示例1-1所示。
BorderPaneborder = new BorderPane();
Labeltoppanetext = new Label("Page Title");
border.setTop(toppanetext);
Label centerpanetext= new Label ("Some data here");
border.setCenter(centerpanetext);
示例1-1 用户界面的java代码
现在看下示例1-2,展示相同的用户界面,但是用FXML标记的。这儿能看到用户界面的层次结构,这更容易依次添加控件构建用户界面。
<BorderPane>
<top>
<Label text="PageTitle"/>
</top>
<center>
<Label text="Some datahere"/>
</center>
</BorderPane>
示例1-2 FXML标记用户界面
1.1.3 FXML的好处
除了提供给web开发者一个熟悉的用户界面设计方法万,FXML还提供如下好处:
Ø 由于场景图在FXML中更透明,这使开发团队更容易创建和维护一个可测试的用户界面;
Ø FXML是非编译语言,无需重编译就可查看变化;
Ø FXML文件内容可以本地化处理。例如,如果一个FXML文件使用en_US本地化加载,它基于下面资源字符串产生 “First Name” 字符串标签:<Label text="%firstName"/>。如果本地化变为fr_FR,这个FXML文件重新加载,这标签将展示“Prénom”。相同的事情对java代码则不行。因为你需要获得相应引用后,必须手动更新每个用户界面元素内容,并正确调用setter。
Ø 可以和任何JVM语言一起使用FXML,诸如Java、Scale或者Clojure。
Ø FXML不局限与MVC模型的视图部分。你可以构造服务、任务或域对象,并且你可以在FXML中使用javascript或其它脚本语言。关于使用脚本示例,请参考本教程“使用脚本语言”部分。
1.2 创建用户界面
通过前述介绍,现在已经对怎么使用FXML有了一定认知,接下来将在教程实战中更好理解。这个实战介绍怎么创建如图2-1所示的登录界面。
图2-1登录界面
图例说明:应用标题为“LoginExample”。标签重叠了一个背景图片。从顶到底,应用程序中的控件是:带文本“Sign In”的标签、带“UserName”的文本框、带“Password”的密码框以及一个提交按钮。
开始前,熟悉下登录界面布局,如图2-2所示。用户界面使用了一个包含两个区域的边格布局(Border Pane)。顶部区域包含一个堆栈布局,内有文字“Label Example”并层叠在一个图片上。中间区域包含一个网格布局,并含有标签、文本框、密码框以及按钮。
图2-2登陆界面布局
1.2.1 准备工作
本部分教程使用到NetBeansIDE。确定你在使用的NetBeans IDE版本支持JavaFX2.0。更多相关细节参考“系统要求”部分。
为了完成这个教程,应该熟悉如何用JavaFX程序性构建用户界面。了解如何与布景图一起工作时特别有益处的。因为FXML的层次结构和JavaFX布景图结构是密切相关的。
1.2.2 创建工程
首先在NetBeans的IDE中创建一个JavaFX工程。
1. 从“文件”(File)菜单,选择“新工程”(New Project);
2. 在JavaFX应用分类中选择JavaFX FXML 应用。点击下一步;
3. 命名工程为FXMLExample并点击“完成”(Finish)。IDE打开带有3个文件的工程:FXMLExample.java,Sample.fxml以及Sample.java;
4. 下载一个淡蓝渐变的背景图片,并保持到桌面,然后拖动到在源代码包目录下的fxmlexample目录。
1.2.3 创建应用基础
每个FXML应用必须包括java代码。最少包括创建stage和scene以及加载launch应用的代码。
打开FXMLExample.java,删除IDE生成的代码,并用示例2-1代码替换。
packagefxmlexample;
importjava.util.ResourceBundle;
importjavafx.application.Application;
importjavafx.fxml.FXMLLoader;
importjavafx.scene.Parent;
importjavafx.scene.Scene;
importjavafx.stage.Stage;
public classFXMLExample extends Application {
@Override
public void start(Stage stage) throwsException {
stage.setTitle("FXMLExample");
Parent root =FXMLLoader.load(getClass().getResource("fxml_example.fxml"),
ResourceBundle.getBundle("fxmlexample.fxml_example"));
Scene scene = new Scene(root, 226,264);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
示例2-1FXMLExampel.java
作为JavaFX程序员,创建布景和舞台以及加载应用的代码应该是熟悉的。下面这行指向于相应的FXML文件:
Parent root =FXMLLoader.load(getClass().getResource("fxml_example.fxml"),ResourceBundle.getBundle("fxmlexample.fxml_example"));
这个FXMLLoader.load()方法从资源文件fxml_example.fxml中加载层级对象,并赋值到名为root的变量。getRsources()实现资源绑定,以便于具体化界面中的字符串,也更容易资源本地化处理。接下来的两部分,将回到资源绑定部分——属性文件和创建FXML源文件。
总体来说,创立布景对象,并设置root变量未场景图的根。FXML中这个根元素将作为布景图的根节点。
1.2.4 创建属性文件
一个最佳实践是具体化用户界面的文本字符串到一个属性文件。可采取如下步骤创建登录界面的属性文件。
1. 在工程窗口,右键点击fxmlexample文件夹,并选择“新建”(new),然后点击“其它”(Other);
2. 在新文件对话框中点击“其它”(Other),选择Properties文件,点击“下一步”(next);
3. 键入fxml_example作为文件名,点击“完成”(Finish)。然后IDE打开以.properties为扩展名的文件;
4. 键入资源名称和值,如下示例2-2所示:
loginExample=LoginExample
signIn=Sign in:
userName=Username:
password=Password:
submit=Submit
1.2.5 创建FXML文件
现在创建一个名称为fxml_example.fxml的FXML文件,并插入xml声明,导入语句。
1. 在项目窗口,在fxmlexample文件夹下右键点击Sample.fxml,选择“重命名”(Rename);
2. 键入fxml_example,点击“OK”;
3. 打开fxml_example文件,删除IDE生成的代码,并以示例2-3的的代码替换。
<?xmlversion="1.0" encoding="UTF-8"?>
<?importjavafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?importjavafx.scene.*?>
<?importjavafx.scene.image.*?>
示例2-3声明和导入语句
所有FXML文件必须以XML声明开始。它定义了XML的版本(1.0)和编码类型(UTF-8)。与在JavaFX里一样,类名必须合乎规范(包括包名),或者也可以使用导入语句导入,如示例2-3所示。如果你喜欢,也可使用具体导入语句指向你的类。
1.2.6 定义边格布局
接下来开始构建用户界面。再导入语句之后插入边格布局内容,如示例2-4所示:
<BorderPanefx:controller="fxmlexample.FXMLExampleController"
xmlns:fx="http://javafx.com/fxml">
<top>
</top>
<center>
</center>
</BorderPane>
示例2-4 边格布局
在这个示例中,场景图的根是边格布局类。它定义了顶部和中部两个区域。fx:controller属性指定控制文件,且必须在根FXML元素内声明。在后续的讲学习更多关于控制器内容。
xmlns:fx=”http://javafx.com/fxml”属性把命名空间映射到URL为http://javafx.com/fxml的位置。必须在FXML根元素中声明命名空间。这个属性可以确保相应JavaFXAPI元素能通过FXML标签来使用。
1.2.7 图片上堆叠文本
接下来在顶部区域嵌套一个堆栈窗格。这个窗格上包含了一个叠加在图片的标签。如图2-3所示。
图2-3 边格布局顶部区域,包含栈窗格
堆窗格代码如示例2-5所示。把下列代码插入到<top>和</top>标签之间。
<StackPane>
<children>
<ImageView>
<image>
<Imageurl="@fx_boxback.jpg"/>
</image>
</ImageView>
<Labeltext="%loginExample" style="-fx-font: NORMAL 20Tahoma;"/>
</children>
</StackPane>
StackPane布局类把它的子节点放在单一堆栈内,每新增一个节点都会防止在前一个节点之上。这种布局模式提供了一种简单的图片上叠加文字的方式。
标签<children>实现把子节点增加到布局图上,这很类似于JavaFX中使用getChildren().add()方法。
图片Image类加载“fx_boxback.jpg”,此文件假设放置在当前FXML文件位置。ImageView类把图片展示在屏幕上。
标签Label类有个文本属性设置资源名称loginExample。在FXML中,一个资源名称由%号操作符唯一指定。加载时,FXML加载器用它的值(LoginExample)替换loginExaple资源名称。
注意:FXML用style属性定义风格。在示例2-5中,Label类使用了style属性设置了字体风格。
另一种定义风格的方法是定义CSS,和在java中使用方法一样。使用CSS可以更容易在以后重定制应用风格。
1.2.8 添加Grid布局和控件
接下来,在边格布局的中部区域嵌入Grid布局。以水平和垂直的方式在Grid布局上放置控件。如图2-4所示。
图2-4 边格布局中部的Grid面板
示例2-6包含了这个grid布设的代码。把它插入到<center>和</center>标签中间。
<GridPanealignment="top_center" hgap="8" vgap="8"
style="-fx-padding: 40 0 00">
<children>
<Labeltext="%signIn"
style="-fx-font:NORMAL 14 Tahoma;"
GridPane.columnIndex="0"GridPane.rowIndex="0"/>
<Labeltext="%userName"
GridPane.columnIndex="0" GridPane.rowIndex="1"
labelFor="$usernameField"/>
<TextField fx:id="usernameField"prefColumnCount="10"
GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Labeltext="%password"
GridPane.columnIndex="0" GridPane.rowIndex="2"
labelFor="$passwordField"/>
<PasswordFieldfx:id="passwordField" prefColumnCount="10"
GridPane.columnIndex="1" GridPane.rowIndex="2"
onAction="#handlePasswordFieldAction"/>
<Buttonfx:id="submitButton" text="%submit"
GridPane.columnIndex="1" GridPane.rowIndex="3"
onAction="#handleSubmitButtonAction"/>
<Labelfx:id="buttonStatusText"
GridPane.columnIndex="1"GridPane.rowIndex="4"
style="-fx-text-fill:#ff0000;"/>
</children>
</GridPane>
示例2-6 带控件的Grid布设
这儿的代码现在看起来很熟悉,但也有些新属性需要解释。GridPane.columnIndex和GridPane.rowIndex属性对应GridPane类的setColumnIndex()和setRowIndex()方法。行列的数量从0开始。例如,第一个Label控件的位置是(0,0),这意味着他在第一行第一列。或是左上角。PrefColumnCount属性被用于TextField和PasswordField控件,预设置10列。
把值fx:id赋予一个文档命名空间里创建变量的元素,以便后续代码中引用。变量引用通过$操作符来标记。在示例2-6中,TextField的ID是usernameField。这个ID被赋予控件Label的labelFor属性,以便为TextField设置标签。
注意PasswordField和Button控件有个onAction属性,这个数字签名引用一个定制方法,这个方法你可以在下一节创建FXMLExampleController类时定义。
尽管FXML是定义应用用户接口结构的便捷方式,但并不提供应用行为的实现方式。这个行为必须在java代码或脚步语言中实现(下一节将描述)。
1.2.9 添加按钮事件
现在,创建一个控制器来处理按钮事件。这个例子演示了java写的事件处理器如何与FXML标记关联。
1. 在工程窗口,在fxmlexample文件夹下右击Sample.java,并选择“Refactor”,然后选择“Rename”(重命名);
2. 键入FXLExampelController并点击“Refactor”;
3. 打开FXMLExampleController.java文件,删除IDE生成代码,并用示例2-7代码替换之。
packagefxmlexample;
importjavafx.event.ActionEvent;
importjavafx.fxml.FXML;
importjavafx.scene.control.Label;
public class FXMLExampleController{
@FXML private Label buttonStatusText;
@FXMLprotected void handleSubmitButtonAction(ActionEvent event) {
buttonStatusText.setText("Submitbutton pressed");
}
@FXML protected voidhandlePasswordFieldAction(ActionEvent event) {
buttonStatusText.setText("Enterkey pressed");
}
}
示例2-7 FXMLExampleController.java
@FXML标注用于标签非公共控制器成员字段域,并且由标签使用相应的处理器方法。另外,对于java编程语言,你也可使用其它编译语言,如Scala来实现控制器。
现在可以运行这个应用程序。在两个输入域键入文本并点击“Submit”(提交)测试下这个应用,看看如何。
完整的应用代码可以下载这个压缩包“FXMLExample.zip”。
1.2.10 使用脚本语言
相对于使用java常见事件处理器,你也能使用提供了JSR223兼容的脚本引擎的语言来创建处理器。诸如JavaScript、Groovy、Jython和Clojure。在登录示例中采用javascript按如下步骤编辑FXML文件。
1. 在fxml_example.fxml文件中,在XML声明后增加Javascript声明。
<?language javascript?>
2. 在按钮标记中,改变下功能名称,调用如下所示:
onAction=”handleSubmitButtonAction(event);”
3. 更新PasswordField标记,类似如下:
onAction=”handlePasswordFieldAction(event);”
4. 从BorderPane标记中删除fx:controller属性,并在<script>标签中直接增加JavaScript功能,如示例2-8所示:
<BorderPanexmlns:fx="http://javafx.com/fxml">
<fx:script>
functionhandleSubmitButtonAction() {
buttonStatusText.setText("Calling the JavaScript");
}
functionhandlePasswordFieldAction(event) {
buttonStatusText.text ="More JavaScript";
}
</fx:script>
示例2-8FXML中 JavaScript
另外一种选择是你可以把Javascript功能放在一个外部文件(如fxml_example.js)中,然后通过下面脚本包含近来:
<fx:script source="fxml_example.js"/>
如果你考虑和FXML一起使用脚本语言,注意,在调试期间可能IDE不支持进入相应脚本代码。
1.2.11 应用式样表
作为内嵌样式替代物,你可以对布景使用式样表,然后设置节点的样式类。按照如下步骤创建式样表,并定义了Grid面板和Label控件的样式。
1. 创建式样表
a. 在工程窗口,右击源码包目录下的fxmlexample文件夹,选择“New”然后选择“Other”;
b. 在新的文件对话框,选择Other,然后选择“CascadingStyle Sheet”,再点击“Next”;
c. 键入fxmlstylesheet,点击“Finish”;
d. 删除IDE生成代码,用示例2-9的代码替换
@charset"utf-8";
/*
Document : FXMLstylesheet.css
*/
.grid-pane {
-fx-padding: 80 0 0 0;
}
.label {
-fx-font: normal 36px Tahoma;
}
2. 打开FXMLExample.java文件在代码行stage.show()前包含如下代码增加样式表到布景中
scene.getStylesheets().add("fxmlexample/fxmlstylesheet.css");
3. 到fxml_example。Fxml文件并增加式样类。
a. 为<String>元素增加导入语句。<?import java.lang.*?>
b. 用示例2-10代码替换GridPane标签内容
<GridPanealignment="top_center" hgap="8" vgap="8">
<styleClass>
<Stringfx:value="grid-pane"/>
</styleClass>
示例2-10
c. 用示例2-11代码替换“Sign In”标签
<Labeltext="%signIn"
GridPane.columnIndex="0"GridPane.rowIndex="0">
<styleClass>
<Stringfx:value="label"/>
</styleClass>
</Label>
在一个对象内使用<styleClass>标签时,式样被应用到所有同类实例(除了类有自己的内联式样)。因此,当你运行FXMLExample应用是,示例2-11式样被应用到不仅仅是Sign标签,也应用到了Username和Password标签。式样没有应用到登录示例的标签,因为他有一个内有式样覆盖了这个样式表。
1.2.12 教程回顾
下面简单回顾一下教程信息点:
l FXML是JavaFX的组件。它是个创建JavaFX应用用户界面的可选项;
l FXML是基于XML的;
l FXML文件作为规则JavaFX工程的一部分,不需要编译;
l FXML层次架构和JavaFX布景图结构对应;
l
开始FXML文件的最佳编码实践是带有XML声明: <?xml version="1.0"encoding="utf-8"?>
;
l
FXML
命名空间必须定义在
XML
代码中组件顶层,以便
FXML
标签整体使用,例如:
<
rootElement xmlns:fx="http://javafx.com/fxml">
;
l 通过资源文件的字符串提取,
FXML
能本地化处理。
资源替代通过%标识;
l FXML
定义样式和
java
代码中
setStyle()
定义
CSS
类似。
既可以使用内联式样,也可使用样式表;
l
给元素
fx:
id赋值
,
以便后续引用。引用时通过
$
标识变量;
l
除了
java
,
FXML
支持其他编译语言实现的控制器,如
Scala
;
l FXML
支持任何
JSR223
兼容的脚本引擎,这样的语言包括
JavaScript
、
Groovy
、
Jython
以及
Clojure
等。
1.3 接下来…
现在已熟悉了FXML,可以进一步查看FXML介绍文档,文档提供了关于FXML语言元素的更多信息。文档包含在javafx.fxml包里,详见这里。
另外,也可自行扩展上面的FXML应用,比如校验用户名不能为空,增加取消按钮等。