JavaFX 8 :Chapter 1 开始(1)

来源:《Learn JavaFX 8: Building User Experience and Interfaces with Java 8》

在这一章节中,你将学到:

  • JavaFX是什么
  • JavaFX的历史
  • 如何去写你的第一个JavaFX应用程序
  • 如何使用NetBeans集成开发环境处理JavaFX应用程序
  • 如何去给JavaFX应用程序传递参数
  • 如何启动JavaFX应用程序
  • JavaFX应用程序的生命周期
  • 如何终止JavaFX应用程序

什么是JavaFX?

JavaFX是一个基于Java的开源框架,用于开发富客户端应用程序。它与市场上的其他框架(例如Adobe Flex 和 Microsoft Silverlight)具有可比性。在Java平台的图形用户界面(GUI,Graphical User Interface)开发技术领域,JavaFX也被视为Swing的继承者。JavaFX库可作为公共Java应用程序编程接口(API)使用。JavaFX包含几个特性使它成为开发富客户机应用程序的首选:

  • JavaFX是用Java编写的,它使您能够利用所有Java特性,如多线程、泛型和lambda表达式。您可以使用您选择的任何Java编辑器(如NetBeans)来编写、编译、运行、调试和打包JavaFX应用程序
  • JavaFX通过它的库支持数据绑定。
  • JavaFX代码可以使用任何支持Java虚拟机(JVM)的脚本语言编写,如Visage、Groovy和Scala。
  • JavaFX提供了两种构建用户界面(UI)的方法:使用Java代码和使用FXML。FXML是一种基于xml的可脚本化标记语言,用于声明性地定义UI。Oracle提供了一个名为Scene Builder的工具,它是FXML的可视化编辑器。
  • JavaFX提供了一套丰富的多媒体支持,例如回放音频和视频。它利用了平台上可用的编解码器。
  • JavaFX允许您在应用程序中嵌入web内容。
  • JavaFX为应用效果和动画提供了开箱即用的支持,这对开发游戏应用程序很重要。您可以通过编写几行代码来实现复杂的动画。

在JavaFX API的背后有许多利用Java本地库和可用硬件和软件的组件。JavaFX组件如图1-1所示。

JavaFX中的GUI作为一个场景图被构建。场景图是被称为节点的视觉元素的集合,按照分层的方式排列。使用公共的JavaFX API可以构建场景图。场景图中的节点可以处理用户的输入和用户的姿势。它们可以有结果、变化和状态。场景图中的节点类型包括简单的UI控件,如按钮、文本字段、二维(2D)和三维(3D)的形状、图像、媒体(音频和视频)、web内容和图表。

Prism是一种用于渲染场景图形的硬件加速图形管道。如果硬件加速呈现在平台上不可用,则使用Java 2D作为后备呈现机制。例如,在使用Java 2D进行渲染之前,它会尝试在Windows上使用DirectX,在Mac Linux和嵌入式平台上使用OpenGL。

Glass Windowing Toolkit提供图形和窗口服务,如使用本机操作系统的窗口和计时器。该工具包还负责管理事件队列。在JavaFX中,事件队列由一个被称为JavaFX Application Thread的单一的、操作系统级的线程管理。所有用户输入的事件都在JavaFX Application Thread上分派。JavaFX要求只能在JavaFX Application Thread上修改实时场景图。

Prism使用一个单独的线程(与JavaFX Application Thread不同)来进行呈现过程。Prism通过在下一帧被处理时渲染一帧来加速处理过程。当场景图被修改时,例如在文本框中输入一些文本,Prism就需要重新渲染场景图。使用一个被称为pluse的事件来实现与Prism同步的场景图。当场景图被修改并且需要重新渲染时,一个pluse事件会在JavaFX Application Thread上排队。pluse事件表明场景图与Prism中的渲染层不同步,应该渲染Prism级别的最新帧。pluse事件被限制在每秒60帧的最大值。

Media Engine负责在JavaFX中提供媒体支持,例如,播放音频和视频。它利用了平台上可用的编解码器。Media Engine使用一个单独的线程来处理媒体帧,并使用了JavaFX Application Thread来同步帧和场景图。该媒体引擎基于GStreamer,这是一个开源的多媒体框架。

Web Engine负责处理嵌入在场景图中的网页内容(HTML)。Prism负责呈现网页内容。该Web Engine基于WebKit,这是一个开源的web浏览器引擎。支持HTML5、层叠样式表(CSS)、JavaScript和文档对象模型(DOM)。

Quantum toolkit是Prism、Glass、Media Engine和Web Engine等底层组件的抽象。它还促进了低级组件之间的协调。

在本书中,我们假设您具有Java编程语言的中级知识。还假定您熟悉Java 8中的新特性,如lambda表达式和Time API。

JavaFX的历史

JavaFX最初是由Chris Oliver在SeeBeyond开发的,它被称为F3(Form Follows Function)。F3是一种用于轻松开发GUI应用程序的Java脚本语言。它提供了声明式语法、静态类型、类型推断、数据绑定、动画、2D图形和Swing组件。SeeBeyond被Sun Microsystems收购,F3在2007年更名为JavaFX。Oracle在2010年收购了Sun Microsystems公司。Oracle在2013年开源了JavaFX。

JavaFX的第一个版本发布于2008年第四季度。JavaFX的当前版本是8.0。版本号从2.2跳到了8.0。从Java 8开始,Java SE和JavaFX的版本号将是相同的。Java SE和JavaFX的主要版本也将同时发布。表1-1列出了JavaFX的发布版本。从Java SE 8发布开始,JavaFX就是Java SE运行时库的一部分。从Java 8开始,不需要任何额外的设置就可以编译和运行JavaFX程序。

  • 它是JavaFX的最初版本。它使用一种称为JavaFX Script的声明语言来编写JavaFX代码。
  • 引入了对JavaFX Mobile的支持。
  • 放弃了对JavaFX脚本的支持。它使用Java语言编写JavaFX代码。放弃了对JavaFX Mobile的支持。
  • 只介绍了对Mac OS桌面的支持。
  • JavaFX版本从2.2升级到8.0。JavaFX和Java SE版本将与Java 8相匹配。

系统需求

你需要在你的电脑上安装以下软件:

  • Java Development Kit 8
  • NetBeans IDE 8.0 or later

用NetBeans IDE来编译和运行本书中的程序不是必要的。然而,NetBeans IDE具有创建、运行和打包JavaFX应用程序的特殊特性,使开发人员的工作更加轻松。您可以使用任何其他IDE,例如Eclipse、JDeveloper或IntelliJ IDEA。

JavaFX运行时库

所有JavaFX类都被打包在一个名为jfxrt.jar的Java Archive(JAR)文件中。JAR文件位于Java主目录下的jre\lib\ext目录中。
如果在命令行上编译和运行JavaFX程序,则不需要担心在CLASSPATH中设置JavaFX运行时JAR文件。Java 8编译器(javac命令)和启动器(Java命令)自动在CLASSPATH中包含了JavaFX运行时JAR文件。
当您创建Java或JavaFX项目时,NetBeans IDE自动在CLASSPATH中包含JavaFX运行时JAR文件。如果您使用的是NetBeans以外的IDE,您可能需要在IDE CLASSPATH中包含jfxrt.jar,以便从IDE内部编译和运行JavaFX应用程序。

JavaFX源码

有经验的开发人员有时更喜欢查看JavaFX库的源代码,以了解事情是如何在幕后实现的。Oracle提供了JavaFX源代码。我们可以在Java主目录里的Java 8中复制源文件,其文件名为javafx-src.zip。将文件解压到一个目录中,并使用您最喜欢的Java编辑器打开源代码。

你的第一个JavaFX应用

让我们编写您的第一个JavaFX应用程序。它应该在窗口中显示文本“Hello JavaFX”。我将采用循序渐进的方法来解释如何开发这第一个应用程序。我将尽可能少地添加代码行,然后解释代码的功能以及为什么需要它。

创建HelloJavaFX类

一个JavaFX应用程序类必须继承javafx.application包中Application类。您将把您的类命名为HelloFXApp,它将存储在com.jdojo.intro包中。表1-1显示了HelloFXApp类的初始代码。注意,HelloFXApp类此时还不能编译,您将在下一节中修复它。

表 1-1. 你的JavaFX应用程序类将继承javafx.application.Application类

// HelloFXApp.java
package com.jdojo.intro;
import javafx.application.Application;
public class HelloFXApp extends Application {
 // Application logic goes here
}

该程序包括一个包声明、一个导入声明和一个类声明。代码中没有类似JavaFX的东西。它看起来像任何其他Java程序。但是,因为HelloFXApp类继承了Application类,您已经满足了JavaFX应用程序的要求之一。

重写start()方法

如果您尝试编译HelloFXApp类,它将在编译时出现以下错误:HelloFXApp is not abstract and does not override abstract method start(Stage) in Application.该错误表明Application类包含一个抽象的start(Stage Stage)方法,该方法在HelloFXApp类中没有被重写。作为一名Java开发人员,您知道接下来要做什么:要么将HelloFXApp类声明为抽象类,要么实现start()方法。下面让我们实现start()方法。关于Application类中的start()方法声明如下:

public abstract void start(Stage stage) throws java.lang.Exception

表1-2展示了修改后的HelloFXApp类代码,它重写了start()方法。

表1-2. 在JavaFX应用程序类中重写start()方法

// HelloFXApp.java
package com.jdojo.intro;
import javafx.application.Application;
import javafx.stage.Stage;
public class HelloFXApp extends Application {
 @Override
 public void start(Stage stage) {
 // The logic for starting the application goes here
 }
}

在修改后的代码中,您做了两件事:

  • 您添加了一个导入语句,以从javafx.Stage包中导入Stage类。
  • 您实现了start()方法。方法的throws子句被删除,根据Java中重写方法的规则,这是被允许的。

start()方法是JavaFX应用程序的入口点。它由JavaFX应用程序启动器调用。注意,start()方法传递了一个Stage类的实例,这个实例被称为应用程序的主要舞台(primary stage)。您可以根据需要在应用程序中创建更多的舞台。但是,主要舞台总是由JavaFX运行时为您创建的。

每个JavaFX应用程序类必须继承Application类,并为start(Stage stage)方法提供实现

展示的舞台

与现实世界中的舞台类似,JavaFX舞台用于显示场景。场景具有可视化——如文本、形状、图像、控件、动画和效果——用户可以与之交互,所有基于GUI的应用程序都是如此。
在JavaFX中,主要舞台是场景的一个容器。根据您的应用程序运行环境的不同,舞台的外观和感觉也不同。您不需要对环境采取任何操作,因为JavaFX运行时将为您处理所有细节。例如,如果应用程序是作为桌面应用程序而运行,主要舞台将是一个带有标题栏和一个显示场景的区域的窗口;如果应用程序是在web浏览器中运行一个applet,主要舞台将是浏览器窗口中的嵌入区域。
由应用程序启动器创建的主要舞台没有场景。在下一节中,您将为您的舞台创建一个场景。
您必须展示舞台,才能看到舞台场景中包含的视觉效果。使用show()方法展示舞台。也可以使用setTitle()方法为舞台设置标题。修改后的HelloFXApp类的代码如表1-3所示。

表1-3. 显示JavaFX应用程序类的主要舞台

// HelloFXApp.java
package com.jdojo.intro;
import javafx.application.Application;
import javafx.stage.Stage;
public class HelloFXApp extends Application {
 @Override
 public void start(Stage stage) {
 // Set a title for the stage
 stage.setTitle("Hello JavaFX Application");
 // Show the stage
 stage.show();
 }
}

启动应用程序

现在可以运行第一个JavaFX应用程序了。你可以使用以下两个选项之一来运行它:

  • 在类中不需要有main()方法来启动JavaFX应用程序。当您运行一个继承自Application类的Java类时,如果正在运行的类不包含main()方法,那么Java命令将启动JavaFX应用程序。
  • 如果您想通过JavaFX应用程序类中的main()方法来调用Application类的launch()静态方法去启动应用程序。launch()方法接受一个String数组作为参数,它是传递给JavaFX应用程序的参数。

如果使用第一种方法,则不需要为HelloFXApp类编写任何额外的代码。如果您使用的是第二种方法,那么带有main()方法的HelloFXApp类修改后的代码如表1-4所示。

表1-4. 没有场景的HelloFXApp JavaFX应用程序

// HelloFXApp.java
package com.jdojo.intro;
import javafx.application.Application;
import javafx.stage.Stage;
public class HelloFXApp extends Application {
 public static void main(String[] args) {
  // Launch the JavaFX application
  Application.launch(args);
 }
 @Override
 public void start(Stage stage) {
  stage.setTitle("Hello JavaFX Application");
  stage.show();
 }
}

main()方法调用了launch()方法,launch()方法将完成一些设置工作,并调用HelloFXApp类的start()方法。start()方法设置主要舞台的标题并显示该舞台。使用下面的命令编译HelloFXApp类:

javac com/jdojo/intro/HelloFXApp.java

使用下面的命令运行HelloFXApp类,将显示一个标题栏窗口,如图1-2所示:

java com.jdojo.intro.HelloFXApp

图1-2. 没有场景的HelloFXApp JavaFX应用程序

窗口的主要区域是空的,这是舞台将展示其场景的内容区域。因为你的舞台还没有场景,所以你会看到一个空白区域。标题栏显示了您在start()方法中设置的标题。
您可以使用窗口标题栏中的“关闭”菜单选项关闭应用程序。在Windows中可以使用Alt + F4来关闭窗口。您可以使用您的平台所提供的任何其他选择来关闭窗口。

Application类的launch()方法在关闭所有窗口或应用程序使用Platform.exit()方法退出之前不会有返回。Platform类在javafx.application包中。

您还没有在JavaFX中看到任何令人兴奋的东西!您需要再等等,直到您在下一节中创建一个场景。

添加main()方法

如前一节所述,Java 8启动器(java命令)不需要main()方法来启动JavaFX应用程序。如果您想运行继承了Application的类,那么java命令将通过自动为您调用Application.launch()方法来启动JavaFX应用程序。
如果您使用NetBeans IDE创建去JavaFX项目并且通过运行JavaFX项目来运行您的应用程序,那么您不需要使用main()方法来启动JavaFX应用程序。但是,当您将JavaFX应用程序类作为一个文件运行时,NetBeans IDE要求您有一个main()方法。比如,通过右键单击选择HelloFXApp文件,并从菜单中选择run file选项。
一些IDEs仍然需要main()方法来启动JavaFX应用程序。因此,本章中的所有示例都将包含main()方法,它将用来启动JavaFX应用程序。

添加一个场景到舞台

在javafx.scene包中Scene类的一个实例代表了一个场景。一个舞台包含了一个场景,一个场景包含了视觉内容。
场景的内容以树状的层次结构排列。在层次结构的顶部是根节点。根节点可能包含子节点,子节点又可能包含它们的子节点,以此类推。您必须有一个根节点来创建一个场景。您将使用VBox作为根节点。VBox代表垂直框,它将子元素垂直排列在一个列中。下面的语句创建了一个VBox:

VBox root = new VBox();

任何继承自javafx.scene.Parent类的节点都可以用作场景的根节点。被称为布局窗格或者容器几个节点,如VBox, HBox, Pane, FlowPane, GridPane或TilePane都可以用作根节点。Group是一个特殊的容器,它将它的子容器分在一组中。

拥有子节点的节点可以提供一个getChildren()方法,该方法返回子节点的一个Observabllist。要向节点添加一个子节点,只需将子节点添加到ObservableList。下面的代码片段向VBox添加了一个Text节点:

// Create a VBox node
VBox root = new VBox();
// Create a Text node
Text msg = new Text("Hello JavaFX");
// Add the Text node to the VBox as a child node
root.getChildren().add(msg);

Scene类包含几个构造函数。您将使用允许您指定根节点和场景大小的构造函数。下面的语句创建一个以VBox为根节点的场景,宽度300px,高度50px:

// Create a scene
Scene scene = new Scene(root, 300, 50);

您需要通过调用Stage类的setScene()方法将场景设置到舞台:

// Set the scene to the stage
stage.setScene(scene);

像这样,您已经使用场景完成了您的第一个JavaFX程序。表1-5包含完整的程序。程序展示如图1-3所示的窗口。

表1-5. 一个具有文本节点场景的JavaFX应用程序

// HelloFXAppWithAScene.java
package com.jdojo.intro;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class HelloFXAppWithAScene extends Application {
 public static void main(String[] args) {
  Application.launch(args);
 }
 @Override
 public void start(Stage stage) {
  Text msg = new Text("Hello JavaFX");
  VBox root = new VBox();
  root.getChildren().add(msg);
  Scene scene = new Scene(root, 300, 50);
  stage.setScene(scene);
  stage.setTitle("Hello JavaFX Application with a Scene");
  stage.show();
 }
}

 

图1-3. 一个JavaFX应用程序,其场景具有一个Text节点

完善HelloFX应用程序

JavaFX能够做的事情比您目前看到的多得多。让我们增强第一个程序并添加一些用户界面元素,例如按钮和文本字段。这一次,用户将能够与应用程序交互。使用Button类的实例去创建一个按钮,如下所示:

// Create a button with "Exit" text
Button exitBtn = new Button("Exit");

当单击按钮时,将触发ActionEvent。您可以添加ActionEvent handler(异步消息处理)来处理事件。使用setOnAction()方法为按钮设置ActionEvent handler。下面的语句为按钮设置ActionEvent handler,用于终止应用程序。您可以使用lambda表达式或匿名类来设置ActionEvent handler。下面的代码片段展示了这两种方法:

// Using a lambda expression
exitBtn.setOnAction(e -> Platform.exit());

// Using an anonymous class
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
...
exitBtn.setOnAction(new EventHandler<ActionEvent>() {
 @Override
 public void handle(ActionEvent e) {
  Platform.exit();
 }
});

表1-6中的程序展示了如何向场景添加更多的节点。程序使用Label类的setStyle()方法将Label的填充颜色设置为蓝色。稍后我将讨论在JavaFX中使用CSS。

表1-6. 在JavaFX应用程序中与用户交互

// ImprovedHelloFXApp.java
package com.jdojo.intro;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ImprovedHelloFXApp extends Application {

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

    @Override
    public void start(Stage stage) {
        Label nameLbl = new Label("Enter your name:");
        TextField nameFld = new TextField();
        Label msg = new Label();
        msg.setStyle("-fx-text-fill: blue;");

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

        // Add the event handler for the Say Hello button
        sayHelloBtn.setOnAction(e -> {
            String name = nameFld.getText();
            if (name.trim().length() > 0) {
                msg.setText("Hello " + name);
            } else {
                msg.setText("Hello there");
            }
        });

        // Add the event handler for the Exit button
        exitBtn.setOnAction(e -> Platform.exit());

        // Create the root node
        VBox root = new VBox();

        // Set the vertical spacing between children to 5px
        root.setSpacing(5);

        // Add children to the root node
        root.getChildren().addAll(nameLbl, nameFld, msg, sayHelloBtn, exitBtn);
        Scene scene = new Scene(root, 350, 150);
        stage.setScene(scene);
        stage.setTitle("Improved Hello JavaFX Application");
        stage.show();
    }
}

改进后的HelloFX程序展示如图1-4所示的窗口。窗口包含两个标签、一个文本字段和两个按钮。该场景使用VBox作为根节点。在文本字段中输入您的姓名,然后单击Say Hello按钮以查看一条Hello消息。单击Say Hello按钮而不输入姓名,将展示消息Hello there。应用程序在Label控件中展示一条消息。单击Exit按钮以退出应用程序。

 图1-4. 一个在场景中几乎没有控件的JavaFX应用程序

使用NetBeans IDE

暂略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值