25、使用 jjs 命令行工具与 Nashorn 开发 JavaFX 应用

使用 jjs 命令行工具与 Nashorn 开发 JavaFX 应用

1. jjs 命令行工具概述

Java 8 提供了一个名为 jjs 的命令行工具,它位于 JDK_HOME\bin 目录下,用于在命令行运行 Nashorn 脚本。 jjs 工具支持多种选项,可以以不同模式运行脚本:
- 交互模式 :如果不指定任何选项或脚本文件, jjs 将以交互模式运行。在交互模式下,输入脚本时会立即进行解释。
- 脚本模式 :使用 –scripting 选项调用 jjs 时,它将以脚本模式运行,允许使用特定于操作系统的 shell 命令,shell 命令需用反引号括起来。此外,脚本模式支持脚本文件中的 heredocs。如果脚本文件以 # 开头,运行该脚本文件会自动启用脚本模式,这支持执行包含 shebang(脚本开头的 #! )的脚本。

2. 在 Nashorn 中使用 JavaFX
2.1 jjs 对 JavaFX 的支持

jjs 命令行工具可用于启动用 Nashorn 脚本创建的 JavaFX 应用程序。要将脚本作为 JavaFX 应用程序运行,需要在 jjs 工具中使用 –fx 选项。例如,运行存储在 myfxapp.js 文件中的脚本作为 JavaFX 应用程序的命令如下:

jjs –fx myfxapp.js
2.2 JavaFX 应用程序在脚本中的结构

在 JavaFX 应用程序中,通常会重写 Application 类的以下三个方法来管理应用程序的生命周期:
- init() 方法:用于初始化应用程序。
- start() 方法:接收应用程序主舞台( Stage )的引用,需要在此方法中填充场景( Scene ),将场景添加到主舞台,并显示舞台。
- stop() 方法:在 JavaFX 应用程序退出时调用。

在 Nashorn 脚本中,也可以采用相同的方式管理 JavaFX 应用程序的生命周期。可以在脚本中定义名为 init() start() stop() 的三个函数,这些函数是可选的。它们对应 Java 类中的三个方法,调用顺序如下:
1. 调用 init() 函数,可在该函数中初始化应用程序。
2. 调用 start() 函数,与 Java 应用程序一样,该函数会接收主舞台的引用。
3. 当 JavaFX 应用程序退出时,调用 stop() 函数。

以下是一个简单 JavaFX 应用程序的 Java 代码示例:

// HelloFX.java
package com.jdojo.script;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class HelloFX extends Application {
    private Text msg;
    private StackPane sp;

    public static void main(String[] args) {
        Application.launch(HelloFX.class);
    }

    @Override
    public void init() {
        msg = new Text("Hello JavaFX from Nashorn!");
        msg.setFont(Font.font("Helvetica", 18));
        sp = new StackPane(msg);
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setTitle("Hello FX");
        stage.setScene(new Scene(sp, 300, 100));
        stage.sizeToScene();
        stage.show();
    }

    @Override
    public void stop() {
        System.out.println("Hello FX application is stopped.");
    }
}

对应的 Nashorn 脚本如下:

// hellofx.js
var msg;
var sp;

function init() {
    msg = new javafx.scene.control.Label("Hello JavaFX from Nashorn!");
    msg.font = javafx.scene.text.Font.font("Helvetica", 18);
    sp = new javafx.scene.layout.StackPane(msg);
}

function start(stage) {
    stage.setTitle("Hello FX");
    stage.setScene(new javafx.scene.Scene(sp, 300, 100));
    stage.sizeToScene();
    stage.show();
}

function stop() {
    java.lang.System.out.println("Hello FX application is stopped.");
}

运行该脚本的命令为:

jjs –fx hellofx.js
2.3 不同函数组合的 JavaFX 应用程序示例
  • 不包含 init() stop() 函数
// hellofx2.js
var msg = new javafx.scene.control.Label("Hello JavaFX from Nashorn!");
msg.font = javafx.scene.text.Font.font("Helvetica", 18);
var sp = new javafx.scene.layout.StackPane(msg);

function start(stage) {
    stage.setTitle("Hello FX");
    stage.setScene(new javafx.scene.Scene(sp, 300, 100));
    stage.sizeToScene();
    stage.show();
}

运行命令:

jjs –fx hellofx2.js
  • 不包含 init() start() stop() 函数
// hellofx3.js
var msg = new javafx.scene.control.Label("Hello JavaFX from Nashorn!");
msg.font = javafx.scene.text.Font.font("Helvetica", 18);
var sp = new javafx.scene.layout.StackPane(msg);
$STAGE.setTitle("Hello FX");
$STAGE.setScene(new javafx.scene.Scene(sp, 300, 100));
$STAGE.sizeToScene();
// $STAGE.show(); // No need to show the primary stage. Nashorn will automatically show it.

运行命令:

jjs –fx hellofx3.js
  • 只包含 init() 函数(错误示例)
// incorrectfxapp.js
var msg;
var sp;

function init() {
    msg = new javafx.scene.control.Label("Hello JavaFX from Nashorn!");
    msg.font = javafx.scene.text.Font.font("Helvetica", 18);
    sp = new javafx.scene.layout.StackPane(msg);
}

$STAGE.setTitle("Hello FX");
$STAGE.setScene(new javafx.scene.Scene(sp, 300, 100));
$STAGE.sizeToScene();

运行该脚本会抛出异常,因为在全局作用域代码执行时, init() 函数尚未被调用, sp 变量仍未定义。如果想使用 init() 函数初始化 JavaFX 应用程序,建议同时提供 init() start() 方法,以确保它们按顺序调用。

2.4 最简单的 JavaFX 应用程序

可以用一行脚本编写最简单的 JavaFX 应用程序,显示一个带有消息的窗口:

// simplestfxapp.js
$STAGE.scene = new javafx.scene.Scene(new javafx.scene.control.Label("Hello JavaFX Scripting"));

运行命令:

jjs –fx simplestfxapp.js

甚至可以不编写任何代码,创建一个空的脚本文件(如 empty.js ),使用以下命令运行:

jjs –fx empty.js

Nashorn 会自动显示一个空的主舞台窗口。

2.5 导入 JavaFX 类型

可以使用 JavaFX 类的全限定名或 Java.type() 函数导入它们。例如,创建一个 Label 的两种方式如下:

// 使用 Label 类的全限定名
var msg = new javafx.scene.control.Label("Hello JavaFX!");

// 使用 Java.type() 函数
var Label = Java.type("javafx.scene.control.Label");
var msg = new Label("Hello JavaFX!");

为了使 JavaFX 脚本更简洁,Nashorn 包含了几个脚本文件,可将 JavaFX 类型作为简单名称导入。在脚本中使用 JavaFX 类的简单名称之前,需要使用 load() 方法加载这些脚本文件。例如, fx:controls.js 脚本文件会将所有 JavaFX 控制类作为简单类名导入。以下是相关脚本文件及其导入的类/包列表:
| Nashorn 脚本文件 | 导入的类/包 |
| — | — |
| fx:base.js | javafx.stage.Stage、javafx.scene.Scene、javafx.scene.Group、javafx/beans、javafx/collections、javafx/events、javafx/util |
| fx:graphics.js | javafx/animation、javafx/application、javafx/concurrent、javafx/css、javafx/geometry、javafx/print、javafx/scene、javafx/stage |
| fx:controls.js | javafx/scene/chart、javafx/scene/control |
| fx:fxml.js | javafx/fxml |
| fx:web.js | javafx/scene/web |
| fx:media.js | javafx/scene/media |
| fx:swing.js | javafx/embed/swing |
| fx:swt.js | javafx/embed/swt |

以下是加载脚本文件并使用 Label 简单名称的示例:

// Import all JavaFX control class names
load("fx:controls.js")

// Use the simple name of the Label control
var msg = new Label("Hello JavaFX!");
3. JavaFX 问候应用程序示例

以下是一个完整的 JavaFX 问候应用程序示例,存储在 greeter.js 文件中:

// greeter.js
// Load Nashorn predefined scripts to import JavaFX specific classes and packages
load("fx:base.js");
load("fx:controls.js");
load("fx:graphics.js");

// Define the start() method of the JavaFX application class
function start(stage) {
    var nameLbl = new Label("Enter your name:");
    var nameFld = new TextField();
    var msg = new Label();
    msg.style = "-fx-text-fill: blue;";

    // Create buttons
    var sayHelloBtn = new Button("Say Hello");
    var exitBtn = new Button("Exit");

    // Add the event handler for the Say Hello button
    sayHelloBtn.onAction = sayHello;

    // Call the same fucntion sayHello() when the user
    nameFld.onAction = sayHello;

    // Add the event handler for the Exit button
    exitBtn.onAction = function() {
        Platform.exit();
    };

    // Create the root node
    var root = new VBox();
    root.style = "-fx-padding: 10;" +
                 "-fx-border-style: solid inside;" +
                 "-fx-border-width: 2;" +
                 "-fx-border-insets: 5;" +
                 "-fx-border-radius: 5;" +
                 "-fx-border-color: blue;";

    // Set the vertical spacing between children to 5px
    root.spacing = 5;

    // Add children to the root node
    root.children.addAll(msg, new HBox(nameLbl, nameFld, sayHelloBtn, exitBtn));

    // Set the scene and title for the stage
    stage.scene = new Scene(root);
    stage.title = "Greeter";

    // Show the stage
    stage.show();

    // A nested function to say hello based on the entered name
    function sayHello(evt) {
        var name = nameFld.getText();
        if (name.trim().length() > 0) {
            msg.text = "Hello " + name;
        }
        else {
            msg.text = "Hello there";
        }
    }
}

运行该脚本的命令如下:

jjs –fx greeter.js

该应用程序会显示一个窗口,输入姓名并按 Enter 键或点击 “Say Hello” 按钮,会显示问候消息。

4. Nashorn 开发 JavaFX 应用的优势

在 Nashorn 中开发 JavaFX 应用程序更加容易,具有以下优点:
- 属性访问便捷 :可以使用属性直接调用 Java 对象的 getter 和 setter 方法,不仅适用于 JavaFX 对象,也适用于所有 Java 对象。例如,在 Java 中使用 root.setSpacing(5) ,在 Nashorn 中可以写成 root.spacing = 5
- 事件处理简单 :可以将匿名函数设置为按钮的事件处理程序,并且可以使用 onAction 属性设置事件处理程序,而无需调用 Button 类的 setOnAction() 方法。例如:

// Add the event handler for the Say Hello button
sayHelloBtn.onAction = sayHello

综上所述,使用 jjs 命令行工具和 Nashorn 脚本可以方便地开发和运行 JavaFX 应用程序,通过灵活运用不同的函数组合和导入方式,能够编写出简洁高效的代码。

使用 jjs 命令行工具与 Nashorn 开发 JavaFX 应用

5. 开发 JavaFX 应用的流程总结

为了更清晰地展示使用 jjs 命令行工具和 Nashorn 开发 JavaFX 应用的流程,我们可以通过以下流程图来概括:

graph LR
    A[准备环境] --> B[创建脚本文件]
    B --> C{选择函数组合}
    C -->|init()、start()、stop()| D[编写完整脚本]
    C -->|无 init() 和 stop()| E[简化脚本]
    C -->|无 init()、start() 和 stop()| F[极简脚本]
    C -->|仅 init()(不推荐)| G[可能出错脚本]
    D --> H[导入 JavaFX 类型]
    E --> H
    F --> H
    G --> H
    H --> I[添加事件处理和布局]
    I --> J[运行脚本]
    J --> K{结果}
    K -->|成功| L[应用运行]
    K -->|失败| M[检查错误并修正]
    M --> B

具体步骤如下:
1. 准备环境 :确保已经安装了包含 jjs 命令行工具的 JDK。
2. 创建脚本文件 :使用文本编辑器创建一个 .js 后缀的脚本文件。
3. 选择函数组合 :根据应用需求选择是否包含 init() start() stop() 函数。
4. 编写脚本 :根据所选的函数组合编写相应的脚本代码。
5. 导入 JavaFX 类型 :可以使用全限定名、 Java.type() 函数或加载 Nashorn 提供的脚本文件来导入 JavaFX 类型。
6. 添加事件处理和布局 :在脚本中添加按钮的事件处理程序,并设置界面布局。
7. 运行脚本 :使用 jjs –fx 命令运行脚本文件。
8. 检查结果 :如果应用成功运行,则开发完成;如果出现错误,检查错误信息并修正脚本。

6. 常见问题及解决方法

在使用 jjs 命令行工具和 Nashorn 开发 JavaFX 应用时,可能会遇到一些常见问题,以下是一些问题及解决方法:
| 问题描述 | 可能原因 | 解决方法 |
| — | — | — |
| 运行脚本时抛出 ClassCastException | 在全局作用域代码执行时, init() 函数尚未被调用,相关变量未定义 | 同时提供 init() start() 方法,确保它们按顺序调用 |
| 无法找到 JavaFX 类 | 未正确导入 JavaFX 类型 | 使用全限定名、 Java.type() 函数或加载 Nashorn 提供的脚本文件来导入 JavaFX 类型 |
| 按钮事件处理程序不生效 | 事件处理程序未正确设置 | 检查事件处理程序的设置,确保使用 onAction 属性或 setOnAction() 方法正确设置事件处理程序 |

7. 总结与展望

使用 jjs 命令行工具和 Nashorn 脚本开发 JavaFX 应用具有诸多优势,如代码简洁、开发便捷等。通过灵活运用不同的函数组合和导入方式,可以编写出高效的 JavaFX 应用程序。同时,Nashorn 提供的属性访问和事件处理方式,使得开发过程更加简单直观。

未来,随着 JavaScript 和 Java 技术的不断发展,使用 Nashorn 开发 JavaFX 应用可能会有更多的优化和改进。例如,可能会有更多的脚本文件用于导入 JavaFX 类型,进一步简化开发过程;或者提供更强大的调试工具,帮助开发者更快地定位和解决问题。

总之,掌握 jjs 命令行工具和 Nashorn 脚本的使用,对于开发 JavaFX 应用是非常有帮助的,希望本文能够为开发者提供一些有用的参考和指导。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值