一、Node类
1.1 引言
将布局之前务必要把Node类和Parent类先说一说,为什么呢?因为我发现了Scene的构造方法,他的形参root的编译类型为Parent类。
因为之前看一些b站的网课么,都说按钮什么这类组件都是Node类继承来的,我胡乱的猜了一下,以为Node继承了Parent,然后组件都是Node类下面的,场景那些就是Parent类继承来的,反正现在知道上面的都是错的。我做了类图才发现我猜错的离谱。
Node 类竟然是Parent的父类!
从图上可以看出Group继承Parent类,首先我们认识一下Parent这个里面的getChildren方法:该方法在parent访问修饰符为protected类型,
再看看都是谁重写了,有四个类:
Group类还在scene包中,所以继承了此方法,而且修改了访问修饰符为public,使得我们可以调用此方法(注意其返回值限定符为Node类,之后会考)。
而region和button位于scene.layout 包中,且该方法没有被重写。
1.2 Node类介绍
引言完毕,进入正题,Node类位于javafx.scene包中,以下是官方文档翻译:
场景图节点的基类。场景图是一组树形数据结构 其中每个项目都有零个或一个父项,并且每个项目都是 具有零个子项的“叶子”或具有零个或多个子项的“分支”。
场景图中的每个项目都称为 .分支节点是 父级类型,其具体子类为“
组
”、“区域
”和“控制”
, 或其子类。Node
叶节点是诸如
矩形
、文本
、图像
视图、媒体视图
、 或其他不能生孩子的叶类。只有一个节点 每个场景图树都没有父节点,称为“根”节点。场景图中可能有几棵树。有些树可能是 a
场景
,在这种情况下,它们有资格被显示。 其他树可能不属于任何场景
。节点在场景图中的任意位置最多可以出现一次。具体说来 节点在以下所有内容中必须出现不超过一次: 作为
场景
的根节点, 父母的子项可观察列表, 或作为节点
的剪辑。场景图不得有循环。如果节点是 树中自身的祖先,考虑
组
内容 可观察列表、父
子项可观察列表和节点
剪辑关系 上述。如果程序将子节点添加到父节点(包括组、区域等) 并且该节点已经是不同父节点的子节点或场景的根节点, 节点将自动(以静默方式)从其以前的父节点中删除。 如果程序尝试以任何其他违反 上述规则,抛出异常,忽略修改尝试 并且场景图将恢复到其先前的状态。
可以重新排列场景图的结构,对于 例如,将子树从场景图中的一个位置移动到 另一个。为此,通常会从中删除子树 在将其插入新位置之前,其旧位置。然而, 如果应用程序如上所述,子树将自动删除 不会显式删除它。
节点对象可以在任何线程上构造和修改,只要它们是 尚未附加到正在
显示
的窗口中
的场景
。 应用程序必须将节点附加到此类场景或在 JavaFX 上修改它们 应用程序线程。JavaFX 应用程序线程是作为启动过程的一部分创建的 JavaFX 运行时。请参阅
应用程序
类和Platform.startup(Runnable)
方法了解更多信息。应用程序不应直接扩展 Node 类。这样做可能会导致 引发的不受支持的操作异常。
1.2.1 字符串标识
场景图中的每个节点都可以被赋予一个唯一的
ID
。此 ID 是 很像HTML标签的“id”属性,因为它取决于设计师 和开发人员,以确保在场景图中是唯一的。 可以使用称为查找(字符串)
的便利函数来查找 在场景图中或 场景图。id 还可用于标识用于应用样式的节点;看 下面的 CSS 部分1.2.2 坐标系
该类定义了传统的计算机图形学“本地” 轴向右增加,轴向下增加的坐标系。形状的具体节点类 提供用于定义形状的几何和位置的变量 在此局部坐标空间内。例如,
矩形
提供 、 、 变量,而Circle
提供 、 和。Node
x
y
x
y
width
height
centerX
centerYradius
在设备像素级别,整数坐标映射到角落和 像素和像素中心之间的裂缝出现在 整数像素位置之间的中点。因为所有坐标值 用浮点数指定,坐标可以精确 指向这些角(当浮点值具有精确整数时 值)或像素上的任何位置。例如,坐标将指向 上左上像素的中心。同样,具有尺寸的矩形 的 by 将从左上角跨越 左上像素在右下角 第 10 条扫描线上的第 10 个像素。最后一个像素的像素中心 该矩形内将在坐标处。
(0.5, 0.5)
Stage
(0, 0)
10
10
Stage(9.5, 9.5)
实际上,大多数节点都对其坐标应用了变换 系统如下所述。因此,上述信息描述 设备坐标与像素网格的对齐方式相对于 转换后的坐标,而不是节点的本地坐标。
Shape
类描述了一些其他内容 有关坐标映射及其方式的重要上下文特定信息 它可能会影响渲染。
1.2.3 转换
任何都可以应用转换。这些包括 平移、旋转、缩放或切变。
Node
翻译转换是转移 节点沿 x 轴或 y 轴的坐标空间。例如,如果您 创建一个在原点绘制的矩形
(x=0, y=0) 宽度为 100,高度为 50,然后沿 x 轴应用平移为 10 的平移
(x=10),则矩形将显示在 (x=10, y=0) 处绘制并保持 宽100点,高50点。请注意,原点已移动,而不是矩形的变量。x
常见的节点转换通常是整数距离的平移 用于在舞台上布置节点。这种整数转换保持 设备像素映射,以便本地坐标仍然是整数 映射到像素之间的裂缝。
旋转变换是旋转坐标空间的变换 围绕指定“枢轴”点的节点,导致节点显示为旋转。 例如,如果您创建一个
矩形
,它是 在原点 (x=0, y=0) 绘制,宽度为 100,高度为 30 和 应用旋转 90 度的旋转
(角度=90)和原点的枢轴(枢轴X=0,枢轴Y=0),然后 矩形将被绘制为好像它的 x 和 y 为零,但其高度为 100 及其宽度 -30。也就是说,就好像一个针被卡在顶部 左角,矩形围绕该矩形顺时针旋转 90 度 针。如果枢轴点放置在矩形的中心 (在点 x=50, y=15)然后矩形将改为旋转 它的中心。请注意,与所有变换一样,x、y、宽度和高度变量 的矩形(相对于局部坐标空间保持)具有 没有改变,而是变换改变了整个坐标空间 的矩形。
缩放转换会导致节点显示得更大或 根据比例因子而减小。缩放会改变坐标空间 的节点使得沿轴的每个单位的距离在本地 坐标乘以比例因子。与旋转一样 转换,缩放转换围绕“枢轴”点应用。 您可以将其视为“缩放”的点。为 例如,如果创建一个 A 为 5、宽度和高度为 50 的
矩形
,并应用具有比例因子 (x=2.0, y=2.0) 的缩放
比例,并且 原点处的枢轴(枢轴 X=0,枢轴 Y=0),整个矩形 (包括笔划)的大小将增加一倍,向右增长和 从原点向下。NodestrokeWidth
剪切变换,有时称为偏斜,有效 旋转一个轴,使 x 轴和 y 轴不再垂直。
可以将多个转换应用于一个节点。自定义转换是使用
转换
列表应用的。预定义的转换使用下面指定的属性应用。 表示变换的矩阵按以下顺序相乘:转换按上述矩阵乘法的相反顺序应用:转换列表的最后一个元素 到第 0 个元素,缩放、旋转、布局和平移。通过按此顺序应用转换,本地边界 节点的坐标将转换为节点父坐标中的边界(请参阅边界矩形部分)。
1.2.4 边框
由于每个节点都有变换,因此每个节点的几何形状 边界矩形可以以不同的方式描述,具体取决于是否 是否考虑转换。
Node
每个都有一个只读
boundsInLocal
变量,该变量指定 in 的边界矩形Node
未转换的本地坐标。 包括 节点的形状几何图形,包括 可能落在局部位置/大小变量之外的非零笔划, 及其剪辑
和效果
变量。NodeboundsInLocal
每个也有一个只读
的边界InParent
变量,该变量 指定所有转换之后的边框 已按照“转换”部分中的指定应用。 它被称为“boundsInParent”,因为矩形将相对于 父级坐标系。这是节点的“视觉”边界。NodeNode
最后,
layoutBounds
变量定义了Node
应用作布局计算的基础,以及 可能与节点的视觉边界不同。对于形状、文本和图像视图, 布局默认情况下,边界仅包括形状几何图形,包括所需的空间 对于非零strokeWidth
,但不包括效果, 剪辑或任何变换。对于可调整大小的类(区域和控件) 布局边界将始终映射到0,0 width x height。
该图显示了没有任何转换的节点及其:
boundsInLocal
如果我们将图像旋转 20 度,我们会得到以下结果:
红色矩形在 节点父节点的坐标空间。保持不变 与第一个图像一样,此图像中的绿色矩形表示节点的坐标空间。
boundsInParent
boundsInLocal
boundsInLocal
这些图像显示填充和描边矩形及其边界。这 第一个矩形
[x:10.0 y:10.0 width:100.0 height:100.0 strokeWidth:0]
具有以下边界边界:[x:10.0 y:10.0 width:100.0 height:100.0]
. 。 第二个矩形[x:10.0 y:10.0 width:100.0 height:100.0 strokeWidth:5]
具有以下边界:[x:7.5 y:7.5 width:105 height:105](默认情况下,描边居中,因此只有一半在外部 原始边界;也可以在内部或外部创建 中风)。 由于两个矩形都没有应用任何变换,boundsInParent
和boundsInLocal
并且是相同的。1.2.5 CSS
Node类包含id、styleClass和样式变量,用于从CSS样式化该节点。在CSS样式表中,id和styleClass变量用于标识应该应用哪些样式的节点。样式变量包含直接应用于此节点的样式属性和值。
有关CSS以及如何在节点上应用CSS样式的更多信息,请参见CSS参考指南。
机器翻译会有文字错位的情况,而且这么长的文字也很难一气读明白。直接看它的实现类就可以了。
2.Node 实现类
Node的父类:Styleable
, EventTarget
直接继承 Node的子类:Camera
, Canvas
, ImageView
, LightBase
, MediaView
, Parent
, Shape
, Shape3D
, SubScene
, SwingNode
下面简述一下这些类:
2.1 Camera 抽象类
用于渲染场景的相机的基类。摄像机定义了场景坐标空间到窗口的映射。Camera是一个抽象类,有两个具体的子类:ParallelCamera和perspective ecamera。
默认摄像机在场景中的位置是,它在场景坐标空间中的投影平面Z = 0,并且它以正Z方向注视屏幕。Z中从相机到投影平面的距离由它所附着的场景的宽度和高度以及它的fieldOfView决定。
该摄像机的nearClip和farClip在眼睛坐标空间中指定。这个空间的定义是,眼睛在它的原点,投影平面是眼睛前面正Z方向上的一个单元。
下面的伪代码是用于计算场景坐标空间中的远近剪辑距离的数学:
final double tanOfHalfFOV = Math.tan(Math.toRadians(FOV) / 2.0); final double halfHeight = HEIGHT / 2; final double focalLenght = halfHeight / tanOfHalfFOV; final double eyePositionZ = -1.0 * focalLenght; final double nearClipDistance = focalLenght * NEAR + eyePositionZ; final double farClipDistance = focalLenght * FAR + eyePositionZ;通用领域
医学
计算机
金融经济
其中FOV是fieldOfView的度数,NEAR是眼空间指定的nearClip, FAR是眼空间指定的farClip。
注意:由于ParallelCamera类没有fieldOfView属性,因此使用了30度垂直视场。
注意:对于fixedEyeAtCameraZero属性为true的PerspectiveCamera,场景坐标空间是标准化的,以适应视图截锥(参见perspective ecamera了解更多细节)。在此模式下,眼睛坐标空间与摄像机节点的局部坐标空间相同。因此,上面提到的转换公式不使用。
应用程序不应该直接扩展Camera类。这样做可能会导致抛出UnsupportedOperationException异常。
比较有意思的是该类的构造器是protected方法,能使用的是他的两个子类:ParallelCamera
, PerspectiveCamera。不过多赘述
2.2 Canvas 类
Canvas是可以使用GraphicsContext提供的一组图形命令在其上绘制的图像。
Canvas节点由宽度和高度构造,宽度和高度指定画布绘图命令呈现到的图像的大小。所有绘图操作都被剪切到该图像的边界。
import javafx.scene.*; import javafx.scene.paint.*; import javafx.scene.canvas.*; Group root = new Group(); Scene s = new Scene(root, 300, 300, Color.BLACK); final Canvas canvas = new Canvas(250,250); GraphicsContext gc = canvas.getGraphicsContext2D(); gc.setFill(Color.BLUE); gc.fillRect(75,75,100,100); root.getChildren().add(canvas);构造器:
Canvas() 创建一个空的Canvas实例。
Canvas(double width, double height) 创建一个具有给定大小的Canvas的新实例。
2.3 ImageView 类
要说最常用的莫过于图片和视频了,这个类属于图片显示类:
ImageView是一个用于绘制图像类加载的图像的节点。
该类允许调整显示图像的大小(保留或不保留原始宽高比),并指定源图像的视口以限制此ImageView显示的像素。
显示图像的示例代码
import javafx.application.Application; import javafx.geometry.Rectangle2D; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.paint.Color; import javafx.stage.Stage; public class HelloImageView extends Application { @Override public void start(Stage stage) { // load the image Image image = new Image("flower.png"); // simple displays ImageView the image as is ImageView iv1 = new ImageView(); iv1.setImage(image); // resizes the image to have width of 100 while preserving the ratio and using // higher quality filtering method; this ImageView is also cached to // improve performance ImageView iv2 = new ImageView(); iv2.setImage(image); iv2.setFitWidth(100); iv2.setPreserveRatio(true); iv2.setSmooth(true); iv2.setCache(true); // defines a viewport into the source image (achieving a "zoom" effect) and // displays it rotated ImageView iv3 = new ImageView(); iv3.setImage(image); Rectangle2D viewportRect = new Rectangle2D(40, 35, 110, 110); iv3.setViewport(viewportRect); iv3.setRotate(90); Group root = new Group(); Scene scene = new Scene(root); scene.setFill(Color.BLACK); HBox box = new HBox(); box.getChildren().add(iv1); box.getChildren().add(iv2); box.getChildren().add(iv3); root.getChildren().add(box); stage.setTitle("ImageView"); stage.setWidth(415); stage.setHeight(200); stage.setScene(scene); stage.sizeToScene(); stage.show(); } public static void main(String[] args) { Application.launch(args); } }
构造器:
ImageView() 分配一个新的ImageView对象。
分配一个新的ImageView对象,其中包含从指定URL加载的图像。 ImageView(Image image) 使用给定的图像分配一个新的ImageView对象。
2.4 MediaView
提供MediaPlayer播放的媒体视图的节点。
下面的代码片段提供了一个Application.start()方法的简单示例,它显示一个视频:
public void start(Stage stage) { // Create and set the Scene. Scene scene = new Scene(new Group(), 540, 209); stage.setScene(scene); // Name and display the Stage. stage.setTitle("Hello Media"); stage.show(); // Create the media source. String source = getParameters().getRaw().get(0); Media media = new Media(source); // Create the player and set to play automatically. MediaPlayer mediaPlayer = new MediaPlayer(media); mediaPlayer.setAutoPlay(true); // Create the view and add it to the Scene. MediaView mediaView = new MediaView(mediaPlayer); ((Group) scene.getRoot()).getChildren().add(mediaView); }
构造器:
MediaView() 创建一个没有关联MediaPlayer的MediaView实例。
MediaView(MediaPlayer mediaPlayer)
创建与指定MediaPlayer关联的MediaView实例。
2.5 Parent 抽象类
目录
场景图中有子节点的所有节点的基类。
这个类处理所有分层场景图操作,包括添加/删除子节点,为布局和呈现标记脏分支,选择,边界计算,以及在每个脉冲上执行布局传递。
有两个直接具体的父类子类
将分组效果和转换应用到子节点集合。
可以使用CSS和布局子节点进行样式化的节点的区域类。
构造器为protect,实现子类为:
2.6 Shape
Shape类为表示某种几何形状形式的对象提供了公共属性的定义。这些属性包括:
要应用到形状的可填充内部的油漆(参见setFill)。
要用于描边形状轮廓的油漆(参见setStroke)。
笔画的装饰性能,包括:
边框边框的宽度。
边框是作为形状边缘的外部填充绘制的,还是作为遵循边界内部的内部边缘绘制的,还是作为沿着边界均匀横跨内外的宽路径绘制的(请参阅StrokeType)。
路径段和路径未闭合端点之间的连接的装饰样式。
的属性。
子类:
Arc
,Circle
,CubicCurve
,Ellipse
,Line
,Path
,Polygon
,Polyline
,QuadCurve
,Rectangle
,SVGPath
,Text
构造器:
Shape() 创建一个Shape的空实例。
2.7 Subscene
SubScene类是场景图中内容的容器。SubScene提供了场景不同部分的分离,每个部分都可以用不同的摄像机、深度缓冲或场景抗锯齿来渲染。子场景被嵌入到主场景或另一个子场景中。
应用程序可以在创建子场景时请求深度缓冲支持或场景抗锯齿支持。只有2D形状且没有任何3D变换的子场景不需要深度缓冲,也不需要场景抗锯齿支持。包含3D形状或带有3D变换的2D形状的子场景可以使用深度缓冲支持来进行适当的深度排序渲染;为了避免深度战斗(也称为Z战斗),在没有3D变换的2D形状上禁用深度测试。有关更多信息,请参阅depthTest。具有3D形状的子场景可以使用场景抗锯齿来提高其渲染质量。
depthBuffer和antiAliasing标志是条件特性。分别使用默认值:false和sceneantialias . disabled。看到ConditionalFeature。SCENE3D获取更多信息。
可能的用例有:
- 混合2D和3D内容
- UI控件的覆盖
- 背景衬垫
- 抬头显示器
一个默认的大灯将被添加到一个包含一个或多个Shape3D节点的子场景中,但没有灯光节点。这个光源是一种颜色。白色点灯放置在相机位置。
构造器:
SubScene(Parent root, double width, double height) 为特定大小的根节点创建子场景。 SubScene(Parent root, double width, double height, boolean depthBuffer, SceneAntialiasing antiAliasing) 构造一个由根组成的SubScene,具有宽度和高度的维度,指定是否为该场景创建深度缓冲区,并指定是否请求场景抗锯齿。
2.8 SwingNode
构造一个由根组成的子场景,根的宽度和高度为单位。这个类用于将Swing内容嵌入到JavaFX应用程序中。要显示的内容是通过setContent(javax.swing.JComponent)方法指定的,该方法接受Swing JComponent的实例。JComponent实例中包含的组件层次结构不应该包含任何重量级组件,否则SwingNode可能无法绘制它。内容会自动重绘。所有的输入和焦点事件都被透明地转发到JComponent实例,并发送给开发人员。
下面是一个典型的模式,演示了如何使用SwingNode:public class SwingFx extends Application { @Override public void start(Stage stage) { final SwingNode swingNode = new SwingNode(); createAndSetSwingContent(swingNode); StackPane pane = new StackPane(); pane.getChildren().add(swingNode); stage.setScene(new Scene(pane, 100, 50)); stage.show(); } private void createAndSetSwingContent(final SwingNode swingNode) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { swingNode.setContent(new JButton("Click me!")); } }); } public static void main(String[] args) { launch(args); } }构造器:
SwingNode() 构造一个SwingNode的对象实例
2.9 Shape3D 抽象类
Shape3D基类为表示某种形式的3D几何形状的对象提供了公共属性的定义。这些属性包括:
- 要应用到形状的可填充内部或轮廓的材质(参见setMaterial(javafx.scene.paint.Material))。
- 绘制模型属性,定义如何渲染它的几何图形(参见 setDrawMode(javafx.scene.shape.DrawMode))。
- 人脸筛选属性,定义要筛选的人脸(参见setCullFace(javafx.scene.shape.CullFace))。
注意,这是一个条件特性。看到ConditionalFeature。SCENE3D获取更多信息。
应用程序不应该直接扩展Shape3D类。这样做可能会导致抛出UnsupportedOperationException异常。
子类:
2.10 LightBase 抽象类
LightBase类是表示光源形式的所有对象的基类。所有的光类型都共享以下在这个类中定义的公共属性:
- 颜色——光源的颜色
- 范围-光源影响的节点列表
- exlusiscope -光源不影响的节点列表
除此之外,每种灯类型都支持一组不同的属性,总结如下表:
旋转和方向
定位和衰减
AmbientLight
✗ ✗ DirectionalLight
✓ ✗ PointLight
✗ ✓ SpotLight
*✓ ✓ *支持聚光灯衰减因子,如其类文档所述。
应用程序不能添加自己的光类型。直接扩展LightBase可能导致抛出UnsupportedOperationException异常。
所有类型的光都不受缩放和剪切变换的影响。
颜色
光源只发出一种颜色的光。被光照射的物体的外观是由光的颜色和物体的材料构成的结果。例如,对于蓝光,白色物体将显示为蓝色,黑色物体将显示为黑色,而(255,0,255)颜色的物体将显示为蓝色,因为光只“选择”材料颜色的蓝色部分。材料-光相互作用的数学定义可以在PhongMaterial中找到。
参见实现说明部分。
作用域
一个灯有一个作用域列表和一个exclusionScope列表,定义哪些节点被它照亮,哪些节点不被它照亮。一个节点只能存在于其中一个列表中:如果它被添加到一个列表中,它就会从另一个列表中无声地删除。如果某个节点不存在于任何列表中,它将递归地从其父节点继承其受影响的状态。一个例外是,一个空作用域的光会隐式地影响它的场景/子场景中的所有节点(除了那些在它的exlusionScope中的节点),就好像场景的根在作用域中一样。
exlususionscope只对那些在光照范围内的节点有用。排除一个节点是一个方便的替代方案,可以遍历场景层次结构,并将所有其他节点添加到灯光的范围。相反,范围可以保持宽广,并且可以使用排除范围排除特定节点。
方向
光的方向是由光的方向矢量属性定义的。光的方向可以通过设置光的旋转变换来旋转。例如,如果方向向量是(1,1,1),而灯不旋转,它将指向(1,1,1)方向,如果灯在y轴上旋转90度,它将指向(1,1,-1)方向。
没有方向的光类型不受旋转变换的影响。距离衰减
光照范围内的任何像素都将被它照亮(除非它属于其范围之外的Shape3D)。从光的位置到像素的位置的距离被测量,并且被检查是否在光的最大范围内,由它的maxRange属性定义。灯的位置可以通过在灯上设置平移变换来改变。
光的强度可以通过衰减来改变距离。衰减公式
Attn = 1 / (ca + la * dist + qa * dist²)
定义3个系数:ca、la和qa,分别控制强度随距离衰减的常数、线性和二次行为。光在空间中某一点的有效颜色为color * attn。虽然不现实,但可以指定衰减系数为负值。这使得所产生的衰减因子为负,这导致光的颜色从材料颜色中减去,而不是添加到材料颜色中,从而创建了一个“阴影施法者”。
为了获得真实的效果,maxRange应该设置为衰减接近于0的距离,因为这将给出一个软截止。
没有距离衰减的光类型不受平移变换的影响。对于这些类型,可以通过使用较深的颜色来降低强度。
注意:这是一个条件特性。看到ConditionalFeature。SCENE3D获取更多信息。
实现注意:
以下应用于光的颜色属性:
- 黑色光被忽略,因为它的贡献为0。
- 光的透明度(alpha)组件被忽略。
这些行为没有指定,将来可能会改变。
子类: