系列中的上一篇
当前教程
使用 FXML
系列中的下一篇

系列中的上一篇: JavaFX 属性

系列中的下一篇: 整合所有内容

使用 FXML

此页面由 Gail C. AndersonPaul Anderson 贡献,根据 UPL 许可,摘自 使用 JavaFX 17 的现代 Java 客户端权威指南,由 Apress 友情提供。

 

使用 FXML 声明场景图节点

您已经了解了 JavaFX API 如何创建场景图节点并为您配置它们。MyShapesMyShapesProperties 程序仅使用 JavaFX 代码来构建和配置这些对象。另一种方法是使用 FXML 声明场景图节点,FXML 是一种基于 XML 的标记语言。FXML 允许您以声明式格式描述和配置场景图。这种方法有几个优点

  • FXML 标记结构是分层的,因此它反映了场景图的结构。
  • FXML 描述您的视图并支持模型-视图-控制器 (MVC) 架构,为大型应用程序提供更好的结构。
  • FXML 减少了您必须编写的用于创建和配置场景图节点的 JavaFX 代码。
  • 您可以使用 Scene Builder 设计 UI。此拖放工具是一个独立的应用程序,它提供场景的视觉渲染。Scene Builder 为您生成 FXML 标记。
  • 您也可以使用文本和 IDE 编辑器编辑 FXML 标记。

FXML 会影响程序的结构。主应用程序类现在调用一个 FXMLLoader。此加载器解析您的 FXML 标记,创建 JavaFX 对象,并将场景图插入根节点处的场景中。您可以拥有多个 FXML 文件,通常每个文件都有一个对应的 JavaFX 控制器类。此控制器类可能包含事件处理程序或其他动态更新场景的语句。控制器还包含管理特定视图的业务逻辑。

让我们回到我们的 MyShapes 示例(现在称为 MyShapesFXML)并使用 FXML 文件作为视图和 CSS 进行样式设置。您可以在下面看到我们程序中的文件,这些文件已排列好,以便与构建工具或 IDE 一起使用。

MyShapesFXML with FXML and CSS

JavaFX 源代码出现在 java 子目录下。resources 子目录包含 FXML 和 CSS 文件(此处为 Scene.fxmlStyles.css)。

此程序包含一个旋转的 StackPaneVBox 控件和第二个 Text 对象。Scene.fxml 描述了我们的场景图:一个顶层 VBox,其中包含一个 StackPaneText 元素。StackPane 包含 EllipseText 形状。

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.effect.DropShadow?>
<?import javafx.scene.effect.Reflection?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.paint.LinearGradient?>
<?import javafx.scene.paint.Stop?>
<?import javafx.scene.shape.Ellipse?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<VBox alignment="CENTER" prefHeight="350.0" prefWidth="350.0" spacing="50.0"
 xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx=http://javafx.com/fxml/1
 fx:controller="org.modernclient.FXMLController">
    <children>
        <StackPane fx:id="stackPane" onMouseClicked="#handleMouseClick"
                               prefHeight="150.0" prefWidth="200.0">
            <children>
                <Ellipse radiusX="110.0" radiusY="70.0">
                    <fill>
                        <LinearGradient endX="0.5" endY="1.0" startX="0.5">
                            <stops>
                                <Stop color="DODGERBLUE" />
                                <Stop color="LIGHTBLUE" offset="0.5" />
                                <Stop color="LIGHTGREEN" offset="1.0" />
                            </stops>
                        </LinearGradient>
                    </fill>
                    <effect>
                        <DropShadow color="GREY" offsetX="5.0"
                                                 offsetY="5.0" />
                    </effect>
                </Ellipse>
                <Text text="My Shapes">
                    <font>
                        <Font name="Arial Bold" size="24.0" />
                    </font>
                    <effect>
                        <Reflection fraction="0.8" topOffset="1.0" />
                    </effect>
                </Text>
            </children>
        </StackPane>
        <Text fx:id="text2" text="Animation Status: ">
            <font>
                <Font name="Arial Bold" size="18.0" />
            </font>
        </Text>
    </children>
</VBox>

顶层容器包含 JavaFX 控制器类的名称,其属性为 fx:controller。VBox 指定其对齐方式、首选大小和间距,然后是其子项:StackPaneText。在这里,我们使用首选大小配置 StackPane。特殊属性 fx:id 指定与该节点相对应的变量名。在 JavaFX 控制器类中,您现在将看到此变量名用 @FXML 注释,用于 StackPane。这就是您在控制器类中访问在 FXML 文件中声明的对象的方式。

此外,StackPane 指定了一个名为 #handleMouseClickonMouseClicked 事件处理程序。此事件处理程序也在 JavaFX 控制器类中用 @FXML 注释。

在这里,StackPane 子项 EllipseText 在 Children FXML 节点内声明。两者都没有关联的 fx:id 属性,因为控制器类不需要访问这些对象。您还会看到线性渐变、阴影和反射效果配置。

请注意,具有 fx:id text2Text 对象出现在 StackPane 定义之后。这使得第二个 Text 对象出现在 VBox 中的 StackPane 下面。我们还指定了一个 fx:id 属性,以便从 JavaFX 控制器访问此节点。 

控制器类

现在让我们向您展示控制器类。您会注意到代码更加紧凑,因为对象实例化和配置代码不再使用 Java 语句完成。所有这些现在都在 FXML 标记中指定。

package org.modernclient;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.RotateTransition;
import javafx.beans.binding.When;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.util.Duration;
import java.net.URL;
import java.util.ResourceBundle;
public class FXMLController implements Initializable {
    @FXML
    private StackPane stackPane;
    @FXML
    private Text text2;
    private RotateTransition rotate;
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        rotate = new RotateTransition(Duration.millis(2500), stackPane);
        rotate.setToAngle(360);
        rotate.setFromAngle(0);
        rotate.setInterpolator(Interpolator.LINEAR);
        rotate.statusProperty().addListener(
                           (observableValue, oldValue, newValue) -> {
            text2.setText("Was " + oldValue + ", Now " + newValue);
        });
        text2.strokeProperty().bind(new When(rotate.statusProperty()
                 .isEqualTo(Animation.Status.RUNNING))
                 .then(Color.GREEN).otherwise(Color.RED));
    }
    @FXML
    private void handleMouseClick(MouseEvent mouseEvent) {
        if (rotate.getStatus().equals(Animation.Status.RUNNING)) {
            rotate.pause();
        } else {
            rotate.play();
        }
    }
}

控制器类实现 Initializable 并覆盖方法 initialize(),该方法在运行时为您调用。重要的是,私有类字段 stackPanetext2@FXML 注释。@FXML 注释将控制器类中的变量名与 FXML 文件中描述的对象关联起来。控制器类中没有创建这些对象的代码,因为 FXMLLoader 会为您完成此操作。

initialize() 方法在这里执行三件事。首先,它创建并配置 RotateTransition 并将其应用于 stackPane 节点。其次,它向转换的状态属性添加一个更改侦听器。第三,text2 描边属性的绑定表达式根据旋转转换的状态指定其颜色。

带有 handleMouseClick()@FXML 注释表示 FXML 文件配置了事件处理程序。此鼠标单击事件处理程序启动和停止旋转转换的动画。 

JavaFX 应用程序类

主应用程序类 MyShapesFXML 现在变得非常简单。它的工作是调用 FXMLLoader,它解析 FXML (Scene.fxml),构建场景图并返回场景图根。您所要做的就是构建场景对象并像以前一样配置舞台,如下所示。

package org.modernclient;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MyShapesFXML extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass()
                           .getResource("/fxml/Scene.fxml"));
        Scene scene = new Scene(root, Color.LIGHTYELLOW);
        scene.getStylesheets().add(getClass()
            .getResource("/styles/Styles.css").toExternalForm());
        stage.setTitle("MyShapesApp with JavaFX");
        stage.setScene(scene);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

 

添加 CSS

现在让我们向您展示如何使用 CSS 整合您自己的样式。JavaFX 的一个优点是它能够使用 CSS 对节点进行样式设置。JavaFX 附带一个默认样式表 Modena.css。您可以增强这些默认样式或用新样式替换它们。我们在文件 Styles.css 中找到的示例 CSS 文件是一个单一样式类 (mytext),它将字体样式设置为斜体

.mytext {
    -fx-font-style: italic;
}

要使用此样式表,您必须首先加载该文件,无论是在应用程序的 start() 方法中还是在 FXML 文件中。将文件添加到可用样式表后,您可以将样式类应用于节点。例如,要将单独定义的样式类应用于特定节点,请使用

text2.getStyleClass().add("mytext");

这里,mytext 是样式类,text2 是程序中的第二个 Text 对象。或者,您可以在 FXML 文件中指定样式表。这种方法的优点是样式现在可以在 Scene Builder 中使用。以下是加载此自定义 CSS 文件并将自定义 CSS 样式类应用于 text2 Text 节点的修改后的 Scene.fxml 文件。

. . .
<VBox alignment="CENTER" prefHeight="350.0" prefWidth="350.0" spacing="50.0"
stylesheets="@../styles/Styles.css"
xmlns="http://javafx.com/javafx/10.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.modernclient.FXMLController">
<children>

<StackPane fx:id="stackPane" onMouseClicked="#handleMouseClick" prefHeight="150.0" prefWidth="200.0">
           . . . code removed . . .
        </StackPane>
        <Text fx:id="text2" styleClass="mytext" text="Animation Status: ">
            <font>
                <Font name="Arial Bold" size="18.0" />
            </font>
        </Text>
    </children>
</VBox>

 

使用 Scene Builder

Scene Builder 最初由 Oracle 开发,现在是开源的。您可以从 Gluon 下载它:https://gluonhq.com/products/scene-builder/。Scene Builder 是一个独立的拖放工具,用于创建 JavaFX UI。您可以在下面看到带有 MyShapesFXML 程序中 Scene.fxml 文件的主要 Scene Builder 窗口。

FXML file with Scene Builder for MyShapesFXML

左上角的窗口显示了 JavaFX 组件库。此库包括容器、控件、形状、3D 等等。从这个窗口,您可以选择组件并将它们拖放到中间的视觉视图或左下角的 Document 窗口中。

Document 窗口显示场景图层次结构。您可以选择组件并在树中移动它们。右侧窗口是 Inspector 窗口,允许您配置每个组件,包括其属性、布局设置和代码。在此图中,StackPaneDocument 层次结构窗口中被选中,并出现在中心视觉视图中。在 Inspector 窗口中,OnMouseClicked 属性设置为 #handleMouseClick,这是 JavaFX 控制器类中对应方法的名称。

Scene Builder 在构建真实的基于表单的 UI 时特别有用。您可以可视化场景层次结构并轻松配置布局和对齐设置。


最后更新: 2023 年 9 月 12 日


系列中的上一篇
当前教程
使用 FXML
系列中的下一篇

系列中的上一篇: JavaFX 属性

系列中的下一篇: 整合所有内容