DOC-10-01 使用JavaFX场景图(Scene Graph)
这篇教程简单介绍了JavaFX场景图的API,提供屏幕图形界面GUI的底层框架。
如果你是一个有经验的Java开发者,并且你已经创建了有GUI的应用程序,那么这是一个好机会。从网页的小程序,到桌面的独立Swing应用,都十分有用。如果你接触过自定义绘制,你就会对Graphics类和相关的方法非常熟悉。尽管传统的方法比较强大,但要精确在屏幕上展示图形,总是需要在开发方面做出许多努力。这项工作往往与大量的应用程序逻辑是分开的。
概述
JavaFX场景图的API使创建图形用户界面更加容易,特别是包括复杂可视效果与转换的时候。一个scene graph(场景图)是一个树状结构,常见于图形应用程序与一些库,如矢量编辑工具,3D库和一些视频游戏。JavaFX场景图是一个retained Mode(保留模式)API,意思是它在你的应用程序中保持为所有图形对象中的一个内部节点。在任何特定的时间,它知道展示什么对象,屏幕什么区域需要重绘,以及如何以最高效的方式展现所有的东西。你将使用场景图API,并让系统自动去处理展现细节,而不是直接调用原始的绘制方法。此方法显著的减少了开发应用程序中所需代码的数量。
JavaFX场景图的个体称为node(节点)。每个节点可分类为branch node(分支节点,表示其有子节点)和leaf node(叶节点,表示没有子节点)。一棵树的第一个节点称为root node(根节点),它没有父节点。图1-1为一张常见的继承图。
图1-1 根节点,分支节点与叶节点
JavaFX API定义了一系列可作为根节点,分支节点与叶节点的类。当以实际类名替换后,一个真实应用程序的同样的图类似于图1-2中展示
图1-2 具体的根节点,分支节点与叶节点的类
在图1-2中,Group对象为根节点。Circle和Rectangle对象为叶节点,因为它们没有而且不能有子节点。Region对象(定义为一个有子节点的,可以使用CSS样式化的屏幕区域)是一个可以有两个以上叶节点(Text和ImageView)分支节点。场景图可以比这个更大,但是基本的父节点包括子节点的组织是在所有的应用中重复出现的模式。
探索API
那么就节点而言到底意味着什么?让我们从创建一个只有根节点的基础应用框架开始,如例1-1所示。
例1-1 创建应用程序框架
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package scenegraphdemo; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage stage) { Group root = new Group(); Scene scene = new Scene(root, 500, 500, Color.BLACK); stage.setTitle("JavaFX Scene Graph Demo"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } |
这段代码的作用是生成了一个如图1-3所示的一个窗口
图1-3 创建一个只有根节点的场景
以下是需要注意的要点:
1. Main类是application.Application的一个扩展。重写了start方法,传入了一个Stage对象(一个最高级的GUI容器)作为参数。
2. 创建了根节点(在这个例子中为scene.Group类的实例),并传入了场景的构造体中,一并传入的有场景的宽度,高度和填充色。
3. 设置了stage的标题,场景和可见度
4. main方法调用了launch()方法。
因为场景的填充色设置为黑色,结果看起来就是如上图所示。根节点没有任何子节点,所以也没有其他的可见项。按照图1-2所示修改,向根节点增加一个子节点。
图1-2 增加一个叶节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package scenegraphdemo; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage stage) { Group root = new Group(); Scene scene = new Scene(root, 500, 500, Color.BLACK); Rectangle r = new Rectangle(25,25,250,250); r.setFill(Color.BLUE); root.getChildren().add(r); stage.setTitle("JavaFX Scene Graph Demo"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } |
按照例1-2修改后,一个250*250的蓝色矩形(叶节点)就出现在了指定的坐标位置。(默认X轴从左到右递增,Y轴从上到下递增。但有可能受转换的影响而变化)图1-4展示了加入叶节点的结果。
图1-4 增加一个叶节点
因为图形对象是受场景图管理,你可以通过一小段附加代码来得到一个有趣的效果。例如你可以简单让将矩形在屏幕上来回变动,同时可以旋转,改变其大小,将其颜色从蓝色转换为红色等。
例1-3使用了转换来实现这些功能
例1-3 动画化场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package scenegraphdemo; import javafx.animation.FillTransition; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; import javafx.animation.Timeline; import javafx.animation.ParallelTransition; import javafx.animation.RotateTransition; import javafx.animation.ScaleTransition; import javafx.animation.TranslateTransition; import javafx.util.Duration; public class Main extends Application { @Override public void start(Stage stage) { Group root = new Group(); Scene scene = new Scene(root, 500, 500, Color.BLACK); Rectangle r = new Rectangle(0, 0, 250, 250); r.setFill(Color.BLUE); root.getChildren().add(r); TranslateTransition translate = new TranslateTransition(Duration.millis(750)); translate.setToX(390); translate.setToY(390); FillTransition fill = new FillTransition(Duration.millis(750)); fill.setToValue(Color.RED); RotateTransition rotate = new RotateTransition(Duration.millis(750)); rotate.setToAngle(360); ScaleTransition scale = new ScaleTransition(Duration.millis(750)); scale.setToX(0.1); scale.setToY(0.1); ParallelTransition transition = new ParallelTransition(r, translate, fill, rotate, scale); transition.setCycleCount(Timeline.INDEFINITE); transition.setAutoReverse(true); transition.play(); stage.setTitle("JavaFX Scene Graph Demo"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } |
这些例子可能比较简单,但是明确并展示了在大多数图形化应用中将会用到的一些重要概念。
javafx.scene包定义了十几个类,在学习API是如何构造时,其中三个类是最重要的:
● Node:所有场景图节点的抽象基础类。
● Parent:所有分支节点的抽象基础类。(此类直接继承Node类)
● Scene:场景图中所有内容的基本容器类。
这些基础类定义了重要的功能,这些功能将被子类继承,包括绘制顺序,可见性,转换的组合以及CSS样式的支持等等。你会发现许多分支节点类都是直接继承Parent类,如Control,Group,Region和WebView。叶节点是通过一些附加包来定义,如javafx.scene.shape和javafx.scene.text。


from: 重磅消息:JavaFX官方文档翻译完毕 | Alan Zeng