使用 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 应用是非常有帮助的,希望本文能够为开发者提供一些有用的参考和指导。
超级会员免费看
655

被折叠的 条评论
为什么被折叠?



