JavaFX FXML
JavaFX FXML是一种XML格式,使我们能够以类似于以HTML编写Web GUI的方式来编写JavaFX GUI。因此,FXML使我们能够将JavaFX布局代码与其余应用程序代码分开。这将清除布局代码和其余应用程序代码。
FXML既可以用于组成整个应用程序GUI的布局,也可以仅用于一部分应用程序GUI的布局。表单,选项卡,对话框等的一部分的布局。
JavaFX FXML示例
开始学习JavaFX FXML的最简单方法是查看一个FXML示例。下面是一个组成简单JavaFX GUI的FXML示例:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Label?> <VBox> <children> <Label text="Hello world FXML"/> </children> </VBox>
本示例定义了一个包含单个Label作为子元素的VBox。 " VBox"组件是JavaFX布局组件。 "标签"仅在GUI中显示文本。如果我们还不了解所有JavaFX组件,请不要担心。一旦开始与他们一起玩,我们将可以使用。
FXML文档中的第一行是XML文档的标准第一行。
以下两行是import语句。在FXML中,我们需要导入要使用的类。必须导入FXML中使用的JavaFX类和核心Java类。
在导入语句之后,我们具有GUI的实际组成。声明了" VBox"组件,并在其" children"属性内声明了一个" Label"组件。结果是Label
实例将被添加到VBox
实例的children
属性中。
加载FXML文件
为了加载FXML文件并创建文件声明的JavaFX GUI组件,请使用FXMLLoader
(javafx.fxml.FXMLLoader
)类。这是完整的JavaFX FXML加载示例,该示例加载FXML文件并返回其中声明的JavaFX GUI组件:
import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.layout.VBox; import javafx.stage.Stage; import java.net.URL; public class FXMLExample extends Application{ public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { FXMLLoader loader = new FXMLLoader(); loader.setLocation(new URL("file:///C:/data/hello-world.fxml")); VBox vbox = loader.<VBox>load(); Scene scene = new Scene(vbox); primaryStage.setScene(scene); primaryStage.show(); } }
为了使该示例正常工作,FXML文件必须位于" C:\ data \ hello-world.fxml"中。如我们所见,文件的位置是通过setLocation()方法设置的。根GUI组件(" VBox"对象)是通过" load()"方法获得的。
在FXML中导入类
为了在FXML中使用Java类,无论是JavaFX GUI组件还是常规Java类,都必须将该类导入FXML文件中。 FXML导入语句如下所示:
<?import javafx.scene.layout.VBox?>
该FXML导入语句导入类javafx.scene.layout.VBox
。
在FXML中创建对象
FXML可以创建JavaFX GUI对象也可以创建非JavaFX对象。有几种方法可以在FXML中创建对象。在以下各节中,我们将看到这些选项是什么。
通过FXML元素和无参数构造函数创建对象
在FXML中创建对象的最简单方法是通过FXML文件中的FXML元素。 FXML中使用的元素名称与Java类名称相同,但没有包名称。通过FXML import语句导入类后,可以将其名称用作FXML元素名称。
在下面的示例中,元素名称VBox
和Label
是有效的,因为这两个类是在FXML文件中使用import语句声明的:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Label?> <VBox> <children> <Label text="Hello world FXML"/> </children> </VBox>
要使用这样的FXML元素创建对象,需要创建的对象的类具有无参数的构造函数。
通过valueOf()方法创建对象
在FXML中创建对象的另一种方法是在要创建对象的类中调用静态的" valueOf()"方法。通过" valueOf()"方法创建对象的方法是在FXML元素中插入" value"属性。这是一个例子:
<?xml version="1.0" encoding="UTF-8"?> <?import com.Hyman.javafx.MyClass?> <MyClass value="The Value"/>
这是相应的MyClass
需要如何工作的方法:
public MyClass { public static MyClass valueOf(String value) { return new MyClass(value); } private String value = null; public MyClass(String value) { this.value = value; } }
注意使用Java String作为参数的static" valueOf()"方法。当FXMLLoader在FXML文件中看到MyClass元素时,将调用此方法。由valueOf()方法返回的对象是插入到FXML文件中组成的GUI中的对象。上面的FXML除了MyClass元素外,不包含其他任何元素,但是可以包含。
请记住,由" valueOf()"方法返回的任何对象都将在对象图(组成的GUI)中使用。如果返回的对象不是包含valueValue()方法的类的实例,而是其他某个类的实例,则该对象仍将在对象图中使用。元素名称仅用于查找包含" valueOf()"方法的类(当FXML元素包含" value"属性时)。
通过工厂方法创建对象
从某种意义上说," valueOf()"方法也是一种基于String参数创建对象的工厂方法。但是我们也可以使用FXMLLoader来调用除valueOf()方法之外的其他工厂方法。
要调用另一个工厂方法来创建对象,我们需要插入fx:factory
属性。 fx:factory属性的值应该是要调用的工厂方法的名称。这是一个例子:
<?xml version="1.0" encoding="UTF-8"?> <?import com.Hyman.javafx.MyClass?> <MyClass fx:factory="instance"/>
MyClass类应类似于上面的FXML示例:
public MyClass { public static MyClass instance() { return new MyClass(); } }
注意instance()
方法。上面的FXML代码段中的fx:factory
属性引用了此方法。
注意,工厂方法必须是无参数方法,才能从fx:factory
属性调用它。
FXML中的属性
一些JavaFX对象具有属性。实际上,大多数人都这样做。我们可以通过两种方式设置属性的值。第一种方法是使用XML属性来设置属性值。第二种方法是使用嵌套的XML元素设置属性值。
为了了解如何更好地在FXML元素中设置属性,让我们看一个示例:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Label?> <VBox spacing="20"> <children> <Label text="Line 1"/> <Label text="Line 2"/> </children> </VBox>
本示例显示了3个属性示例。第一个例子是VBox
元素中的spacing
属性。在spacing
属性中设置的值作为参数传递给基于VBox
元素创建的VBox
对象的setSpacing()
方法。
第二个例子是嵌套在VBox
元素内的children
元素。该元素对应于VBox类的getChildren()方法。嵌套在child元素内的元素将转换为JavaFX组件,这些组件将添加到从父VBox元素表示的VBox对象的getChildren()方法获得的集合中。
第三个示例是嵌套在"孩子"内部的两个"标签"元素的"文本"属性。文本属性的值将作为参数传递给由标签元素创建的标签对象的setText()属性。
属性名称匹配
FXML认为"属性"是通过getter和setter访问的成员变量。例如。 getText()和setText()。
从上一节的示例中可以看到,JavaFX类的属性名称通过以下方式与属性和元素名称匹配:
- 删除属性名称中的所有获取/设置。
- 将属性名称的第一个剩余字符转换为小写。
因此,getter方法" getChildren"将首先被简化为" Children",然后将其简化为" children"。类似地,setter方法的setText方法将简化为Text,然后简化为text。
默认属性
JavaFX组件可以具有默认属性。这意味着,如果FXML元素包含未嵌套在property元素内的子元素,则假定这些子元素属于默认属性。
让我们来看一个例子。 VBox类具有child属性作为默认属性。这意味着我们可以省略" children"元素。因此,此FXML:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Label?> <VBox spacing="20"> <children> <Label text="Line 1"/> <Label text="Line 2"/> </children> </VBox>
可以缩短为:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Label?> <VBox spacing="20"> <Label text="Line 1"/> <Label text="Line 2"/> </VBox>
然后,假定两个" Label"元素属于" VBox"的默认属性,即" children"属性。
默认属性用JavaFX批注" @DefaultProperty(value =" propertyName")"标记,其中,值是应为默认属性的属性的名称。例如,@DefaultProperty(value =" children")声明会将child属性设为默认属性。
FXML命名空间
FXML具有可以在FXML文件的根元素上设置的名称空间。一些FXML属性(例如fx:id
属性)需要FXML名称空间(请参阅本FXML教程的下一节)。
在FXML文件的根元素上设置FXML命名空间如下所示:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <VBox xmlns:fx="http://javafx.com/fxml"> </VBox>
FXML名称空间由属性声明xmlns:fx =" http://javafx.com/fxml"
声明。
FXML元素ID
我们可以为FXML元素分配ID。这些ID可用于引用FXML文件中其他位置的FXML元素。通过FXML名称空间的id属性指定FXML元素的ID。这是为FXML元素指定和ID的示例:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Label?> <VBox xmlns:fx="http://javafx.com/fxml"> <Label fx:id="label1" text="Line 1"/> </VBox>
注意标签元素中的属性声明fx:id =" label1"。此属性声明该"标签"元素的ID。现在,可以通过FXML文档中其他位置的ID" label1"引用此特定的" Label"元素。例如,此ID可用于引用CSS中的FXML元素。稍后在本FXML教程中,我们将看到按ID引用FXML元素的示例。
FXML事件处理程序
可以从定义JavaFX对象的FXML文件内部在JavaFX对象上设置事件处理程序。我们可能希望从Java代码中设置高级事件处理程序,但对于简单的事件处理程序,可以从FXML设置它们。
为了定义事件处理程序,我们需要使用一个script
元素。这是FXML脚本元素的外观:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.Label?> <VBox xmlns:fx="http://javafx.com/fxml"> <Label fx:id="label1" text="Button not clicked"/> <Button fx:id="button1" text="Click me!" onAction="reactToClick()"/> <fx:script> function reactToClick() { label1.setText("Button clicked"); } </fx:script> </VBox>
此示例显示了两个有趣的FXML概念。第一个概念是从FXML内部向JavaFX组件添加事件侦听器。 Button元素通过其onAction属性声明事件监听器。该属性值声明对" reactToClick()"函数的调用,该函数在FXML文件下方的" script"元素中定义。
第二个概念是通过FXML文件中的JavaFX组件ID对其进行引用。在script元素中声明的reactToClick()方法内部,通过以下语句通过其ID label1引用Label元素:
label1.setText("Button clicked");
onAction事件监听器属性对应于Button组件的onAction事件。我们也可以通过Java代码,通过Button``setOnAction()
方法来设置此事件侦听器。我们也可以使用与其他属性相同的名称匹配规则,通过将来自相应JavaFX组件的事件监听器方法与FXML属性进行匹配,来为FXML中的其他事件设置监听器。
FXML CSS样式
可以设置FXML文件中声明的JavaFX组件的样式。我们可以通过在FXML元素中嵌入一个style元素来实现。这是CSS样式化FXML文件中的JavaFX按钮的示例:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Button?> <VBox xmlns:fx="http://javafx.com/fxml"> <Button text="Click me!"/ onAction="reactToClick()"> <style> -fx-padding: 10; -fx-border-width: 3; </style> </Button> </VBox>
此示例将-fx-padding
CSS属性设置为10,并将-fx-border-width
属性设置为3. 由于style
元素嵌套在button
元素内,因此将应用这些CSS样式。到那个" button"元素。
FXML控制器类
我们可以为FXML文档设置控制器类。 FXML控制器类可以将FXML文件中声明的GUI组件绑定在一起,从而使控制器对象充当介体(设计模式)。
有两种方法可以为FXML文件设置控制器。设置控制器的第一种方法是在FXML文件中指定它。第二种方法是在用于加载FXML文档的FXMLLoader
实例上设置控制器类的实例。此JavaFX FXML教程将在以下各节中显示这两个选项。
在FXML中指定控制器类
控制器类是使用fx:controller属性在FXML文件的根元素中指定的。这是在FXML中指定控制器的示例:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.control.Button?> <VBox xmlns:fx="http://javafx.com/fxml" fx:controller="com.Hyman.javafx.MyFxmlController" > <Button text="Click me!"/ onAction="reactToClick()"> </Button> </VBox>
注意根元素(" VBox"元素)中的" fx:controller"属性。此属性包含控制器类的名称。加载FXML文件时,将创建此类的实例。为此,控制器类必须具有无参数的构造函数。
在FXMLLoader上设置控制器实例
在" FXMLLoader"上设置控制器实例时,必须首先创建控制器类的实例,然后在" FXMLLoader"上设置该实例。这是在FXMLLoader实例上设置控制器实例的示例:
MyFxmlController controller = new MyFxmlController(); FXMLLoader loader = new FXMLLoader(); loader.setController(controller);
将JavaFX组件绑定到控制器字段
我们可以将FXML文件中的JavaFX组件绑定到控制器类中的字段。要将JavaFX组件绑定到控制器类中的字段,我们需要为JavaFX组件的FXML元素提供一个fx:id属性,该属性具有控制器字段的名称以将其绑定为值。这是一个示例控制器类:
public class MyFxmlController { public Label label1 = null; }
这是FXML文件,带有一个" Label"元素绑定到控制器类的" label1"字段:
<VBox xmlns:fx="http://javafx.com/fxml" > <Label fx:id="label1" text="Line 1"/> </VBox>
注意fx:id属性的值如何具有label1的值,该值与应该绑定到其的控制器类中的字段名相同。
控制器中的引用方法
可以从FXML引用控制器实例中的方法。例如,我们可以将JavaFX GUI组件的事件绑定到控制器的方法。这是将JavaFX组件的事件绑定到控制器中的方法的示例:
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="com.Hyman.javafx.MyFxmlController" spacing="20"> <children> <Label fx:id="label1" text="Line 1"/> <Label fx:id="label2" text="Line 2"/> <Button fx:id="button1" text="Click me!" onAction="#buttonClicked"/> </children> </VBox>
这个例子将Button的onAction事件绑定到控制器类中的buttonClicked方法。启用事件绑定的控制器类如下所示:
import javafx.event.Event; import javafx.fxml.FXML; import javafx.scene.control.Label; public class MyFxmlController { @FXML public void buttonClicked(Event e){ System.out.println("Button clicked"); } }
注意在buttonClicked方法上方的@FXML批注。此注释将方法标记为FXML绑定的目标。还要注意,在FXML文件中引用了名称" buttonClicked"。
从FXMLLoader获取控制器实例
一旦FXMLLoader实例加载了FXML文档,就可以通过FXMLLoader getController()方法获取对控制器实例的引用。这是一个例子:
MyFxmlController controllerRef = loader.getController();