系列中的上一篇
当前教程
效果、渐变和动画
系列中的下一篇

系列中的上一篇: JavaFX 布局控件

系列中的下一篇: JavaFX 属性

效果、渐变和动画

本页面由 Gail C. AndersonPaul Anderson 贡献,根据 UPL 许可,并来自 使用 JavaFX 17 的现代 Java 客户端的权威指南,由 Apress 友好提供。

 

增强 MyShapes 应用程序

JavaFX 相比于旧的 UI 工具包的一个优势在于,您可以轻松地将效果、渐变和动画应用于场景图中的节点。我们将反复回到场景图节点的概念,因为这是 JavaFX 运行时高效渲染应用程序视觉部分的方式。现在让我们对 MyShapes 进行一些修改,向您展示其中的一些功能。由于 JavaFX 能够对颜色进行插值,因此您可以使用颜色来定义渐变。渐变可以为形状提供深度,并且可以是径向的或线性的。让我们向您展示一个线性渐变。  

线性渐变

线性渐变需要两种或多种颜色,称为停止点。渐变停止点由颜色和 0 到 1 之间的偏移量组成。此偏移量指定在渐变中放置颜色的位置。渐变计算从一个颜色停止点到下一个颜色停止点的比例阴影。在我们的示例中,我们将使用三个颜色停止点:Color.DODGERBLUEColor.LIGHTBLUEColor.GREEN。第一个停止点将具有偏移量 0,第二个偏移量 .5,第三个偏移量 1.0,如下所示

Stop[] stops = new Stop[] { new Stop(0, Color.DODGERBLUE),
        new Stop(0.5, Color.LIGHTBLUE),
        new Stop(1.0, Color.LIGHTGREEN)};

LinearGradient 构造函数指定 x 轴范围,然后是 y 轴范围。以下线性渐变具有恒定的 x 轴,但其 y 轴变化。这称为垂直渐变。

// startX=0, startY=0, endX=0, endY=1
LinearGradient gradient = new LinearGradient(0, 0, 0, 1, true,CycleMethod.NO_CYCLE, stops);

布尔值 true 表示渐变延伸到整个形状(其中 0 和 1 与形状成比例),而 NO_CYCLE 表示模式不重复。布尔值 false 表示渐变的 x 和 y 值相对于父级的本地坐标系。要创建水平渐变,请指定 x 轴的范围,并使 y 轴保持恒定,如下所示

// startX=0, startY=0, endX=1, endY=0
LinearGradient gradient = new LinearGradient(0, 0, 1, 0, true,CycleMethod.NO_CYCLE, stops);

其他组合允许您指定对角线渐变或反向渐变,其中颜色以相反的顺序出现。  

阴影

接下来,让我们向椭圆添加一个阴影效果。您指定阴影的颜色,以及半径和 x 和 y 偏移量。半径越大,阴影越大。偏移量表示阴影相对于形状外边缘的位置。在这里,我们指定半径为 30 像素,偏移量为形状右侧和下方 10 像素

ellipse.setEffect(new DropShadow(30, 10, 10, Color.GRAY));

这些偏移量模拟了从场景左上角发出的光源。当偏移量为 0 时,阴影会围绕整个形状,就好像光源直接照射在场景上方一样。  

反射

反射效果会镜像组件并逐渐淡化为透明,具体取决于您如何配置其顶部和底部不透明度、分数和偏移量。让我们向文本节点添加一个反射效果。我们将使用 .8 作为分数,这样反射将是反射组件的十分之八。偏移量指定反射从底部边缘下方多少像素开始。我们指定 1 像素(默认值为 0)。反射从完全不透明(顶部不透明度)开始,并过渡到完全透明(底部不透明度),除非您修改顶部和底部不透明度值

Reflection r = new Reflection();
r.setFraction(.8);
r.setTopOffset(1.0);
text.setEffect(r);

您可以在下面观察增强的 MyShapes 程序在窗口中运行。您会看到线性渐变填充应用于椭圆,椭圆上有一个阴影,以及应用于文本的反射效果。 增强的 MyShapes 应用程序 (MyShapes2)  

配置操作

现在是让我们的应用程序做一些事情的时候了。JavaFX 使用鼠标、手势、触摸或按键定义了各种类型的标准输入事件。这些输入事件类型都有特定的处理程序来处理它们。

现在让我们保持简单。我们将向您展示如何编写一个事件处理程序来处理单个鼠标单击事件。我们将创建处理程序并将其附加到场景图中的节点。程序的行为将根据哪个节点获取处理程序而有所不同。我们可以在文本、椭圆或堆栈窗格节点上配置鼠标单击处理程序。以下是向文本节点添加操作事件处理程序的代码

text.setOnMouseClicked(mouseEvent -> {
    System.out.println(mouseEvent.getSource().getClass() + " clicked.");
});

当用户单击文本内部时,程序会显示行 class javafx.scene.text.Text clicked。

如果用户单击背景区域(堆栈窗格)或椭圆内部,则不会发生任何事情。如果我们将相同的侦听器附加到椭圆而不是文本,我们将看到行 class javafx.scene.shape.Ellipse clicked。

请注意,由于文本对象出现在堆栈窗格中椭圆的前面,因此单击文本对象不会调用事件处理程序。即使这些场景图节点彼此叠加,它们在层次结构中也是独立的节点。也就是说,一个节点不在另一个节点内部;相反,它们都是由堆栈窗格管理的独立叶节点。在这种情况下,如果您希望两个节点都响应鼠标单击,则需要将鼠标事件处理程序附加到这两个节点。或者,您也可以只将一个事件处理程序附加到堆栈窗格节点。然后,窗口内部的任何鼠标单击都会触发处理程序,并显示以下输出行:class javafx.scene.layout.StackPane clicked。让我们做一些更令人兴奋的事情,并向 MyShapes 程序应用动画。  

动画

当您使用内置的转换 API 时,JavaFX 使动画变得非常容易。每个 JavaFX 转换类型都控制一个或多个节点(或形状)属性。例如,FadeTransition 控制节点的不透明度,随着时间的推移改变属性。要逐渐淡出某个东西,您需要将其不透明度从完全不透明(1)更改为完全透明(0)。TranslateTransition 通过修改其 translateX 和 translateY 属性(或如果您使用 3D 则为 translateZ)来移动节点。

您可以使用 ParallelTransition 并行播放多个转换,或者使用 SequentialTransition 顺序播放。要控制两个顺序转换之间的计时,请使用 PauseTransition 或使用 Transition 方法 setDelay() 配置转换开始之前的延迟。您还可以使用 Transition 操作事件处理程序属性 onFinished 定义 Transition 完成时的操作。

过渡从方法play()playFromStart()开始。方法play()从当前时间开始过渡;方法playFromStart()始终从时间 0 开始。其他方法包括stop()pause()。您可以使用getStatus()查询过渡的状态,它将返回以下之一Animation.Status枚举值:RUNNINGPAUSEDSTOPPED

所有过渡都支持通用属性duration, autoReverse, cycleCount, onFinished, currentTime,以及节点或形状(对于特定于形状的过渡)。

现在让我们为我们的MyShapes程序定义一个RotateTransition。当用户在窗口内单击时,旋转开始。

public class MyShapes extends Application {
    @Override
    public void start(Stage stage) throws Exception {
         . . .
        // Define RotateTransition
        RotateTransition rotate = new RotateTransition(
                       Duration.millis(2500), stackPane);
        rotate.setToAngle(360);
        rotate.setFromAngle(0);
        rotate.setInterpolator(Interpolator.LINEAR);
        // configure mouse click handler
        stackPane.setOnMouseClicked(mouseEvent -> {
            if (rotate.getStatus().equals(Animation.Status.RUNNING)) {
                rotate.pause();
            } else {
                rotate.play();
            }
        });
        . . .
    }
}

RotateTransition构造函数指定持续时间为 2500 毫秒,并将过渡应用于StackPane节点。旋转动画从角度 0 开始,以线性方式进行到角度 360,提供一次完整的旋转。当用户在StackPane布局控件内任何位置单击时,动画开始。

在这个示例中,有一些有趣的事情需要注意。首先,因为我们在StackPane节点上定义过渡,所以旋转将应用于所有StackPane的子节点。这意味着不仅EllipseText形状会旋转,而且阴影和反射效果也会旋转。

其次,事件处理程序检查过渡状态。如果动画正在进行(正在运行),则事件处理程序会暂停过渡。如果它没有运行,则它会使用play()启动它。因为play()从过渡的当前时间开始,所以pause()后跟play()将从暂停的地方恢复过渡。

您可以在下面看到程序在旋转过渡期间运行。

MyShapes application with RotateTransition (MyShapes2)


上次更新: 2023 年 9 月 12 日


系列中的上一篇
当前教程
效果、渐变和动画
系列中的下一篇

系列中的上一篇: JavaFX 布局控件

系列中的下一篇: JavaFX 属性