JavaFX 效果
最后修改于 2023 年 10 月 18 日
JavaFX 包含 javafx.scene.effect 包,它包含一组执行各种视觉效果的类。 在本章中,我们创建一个 DropShadow,一个 Reflection,一个 Lighting,一个 GaussianBlur,一个 SepiaTone 和一个 PerspectiveTransform 效果。 我们还展示了如何组合多个效果。
效果通过节点的 effectProperty 使用 setEffect 方法应用。
JavaFX 阴影
DropShadow 是一种高级效果,它使用指定的颜色、半径和偏移量在内容后面呈现阴影。
package com.zetcode;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class DropShadowEx extends Application {
@Override
public void start(Stage stage) {
initUI(stage);
}
private void initUI(Stage stage) {
var root = new StackPane();
var rect = new Rectangle(0, 0, 100, 100);
rect.setFill(Color.GREENYELLOW);
var ds = new DropShadow(15, Color.DARKGREEN);
rect.setEffect(ds);
root.getChildren().add(rect);
var scene = new Scene(root, 250, 200, Color.WHITESMOKE);
stage.setTitle("DropShadow");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
该示例在矩形周围创建一个阴影。
var rect = new Rectangle(0, 0, 100, 100); rect.setFill(Color.GREENYELLOW);
构建一个黄绿色矩形形状。
var ds = new DropShadow(15, Color.DARKGREEN);
创建一个 DropShadow 效果。构造函数接受半径和颜色。
rect.setEffect(ds);
使用 setEffect 方法应用效果。
JavaFX 反射
Reflection 是一种效果,它在实际输入内容下方呈现输入内容的反射版本。
package com.zetcode;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.Reflection;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class ReflectionEx extends Application {
@Override
public void start(Stage stage) {
initUI(stage);
}
private void initUI(Stage stage) {
var root = new StackPane();
var text = new Text();
text.setText("ZetCode");
text.setFill(Color.STEELBLUE);
text.setFont(Font.font("Serif", FontWeight.BOLD, 60));
var ref = new Reflection();
text.setEffect(ref);
root.getChildren().add(text);
var scene = new Scene(root, 300, 250, Color.WHITESMOKE);
stage.setTitle("Reflection");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
该示例将 Reflection 效果应用于 Text 节点。
var text = new Text();
text.setText("ZetCode");
text.setFill(Color.STEELBLUE);
text.setFont(Font.font("Serif", FontWeight.BOLD, 60));
创建一个 Text 控件。它的颜色是钢蓝色。字体加粗并放大。
var ref = new Reflection(); text.setEffect(ref);
创建一个默认的 Reflection 并将其应用于文本控件。
JavaFX 照明
Lighting 模拟一个照射到给定内容上的光源,可用于使平面对象具有更逼真的三维外观。Light 源的 setAzimuth 方法设置方位角 — 光源的方向角。
package com.zetcode;
import javafx.application.Application;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.effect.Light;
import javafx.scene.effect.Lighting;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class LightingEx extends Application {
@Override
public void start(Stage stage) {
initUI(stage);
}
private void initUI(Stage stage) {
var root = new VBox(30);
root.setPadding(new Insets(10));
var azimuth = new SimpleDoubleProperty(0);
Light.Distant light = new Light.Distant();
light.setAzimuth(0);
var lighting = new Lighting(light);
lighting.setSurfaceScale(5.0);
var text = new Text();
text.setText("ZetCode");
text.setFill(Color.LIGHTSKYBLUE);
text.setFont(Font.font(null, FontWeight.BOLD, 60));
var slider = new Slider(1, 360, 0);
azimuth.bind(slider.valueProperty());
slider.valueProperty().addListener(event -> {
light.setAzimuth(azimuth.get());
lighting.setLight(light);
text.setEffect(lighting);
});
text.setEffect(lighting);
root.getChildren().addAll(slider, text);
var scene = new Scene(root, 300, 250, Color.WHITESMOKE);
stage.setTitle("Lighting");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
该示例将 Lighting 效果应用于 Text 控件。光的方位角由 Slider 控制。
Light.Distant light = new Light.Distant(); light.setAzimuth(0);
创建一个 Light 源。
var lighting = new Lighting(light);
此行创建一个带有指定光照的 Lighting 新实例。
var text = new Text();
text.setText("ZetCode");
text.setFill(Color.LIGHTSKYBLUE);
text.setFont(Font.font(null, FontWeight.BOLD, 60));
这是设置 Lighting 效果的 Text 控件。
var slider = new Slider(1, 360, 0);
azimuth.bind(slider.valueProperty());
slider.valueProperty().addListener(event -> {
light.setAzimuth(azimuth.get());
lighting.setLight(light);
text.setEffect(lighting);
});
Slider 控件管理光源的方位角。
JavaFX 高斯模糊
GaussianBlur 是一种使用高斯卷积核的模糊效果,具有可配置的半径。
package com.zetcode;
import javafx.application.Application;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class GaussianBlurEx extends Application {
@Override
public void start(Stage stage) {
initUI(stage);
}
private void initUI(Stage stage) {
var root = new VBox(30);
root.setPadding(new Insets(10));
var radius = new SimpleDoubleProperty(0);
var blurredText = new Text("Inception");
blurredText.setFont(Font.font(38));
var slider = new Slider(1, 20, 1);
radius.bind(slider.valueProperty());
slider.valueProperty().addListener(event -> {
blurredText.setEffect(new GaussianBlur(radius.get()));
});
root.getChildren().addAll(slider, blurredText);
var scene = new Scene(root, 300, 250, Color.WHITESMOKE);
stage.setTitle("Blur effect");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
该示例将 GaussianBlur 效果应用于 Text 控件。模糊的半径由 Slider 控制。
var blurredText = new Text("Inception");
blurredText.setFont(Font.font(38));
模糊效果将应用于此文本控件。
var slider = new Slider(1, 20, 1);
radius.bind(slider.valueProperty());
slider.valueProperty().addListener(event -> {
blurredText.setEffect(new GaussianBlur(radius.get()));
});
Slider 控件管理 GaussianBlur 效果的 radius 属性。
JavaFX 褐色调
SepiaTone 是一种过滤器,可产生褐色调效果,类似于古董照片。
package com.zetcode;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.CacheHint;
import javafx.scene.Scene;
import javafx.scene.effect.Effect;
import javafx.scene.effect.SepiaTone;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class SepiaToneEx extends Application {
@Override
public void start(Stage stage) {
initUI(stage);
}
private void initUI(Stage stage) {
var root = new StackPane();
var image = new Image("file:src/main/resources/mushroom.png");
var iw = new ImageView(image);
var sepia = new SepiaTone();
iw.effectProperty().bind(
Bindings.when(iw.hoverProperty())
.then((Effect) sepia)
.otherwise((Effect) null)
);
iw.setCache(true);
iw.setCacheHint(CacheHint.SPEED);
root.getChildren().add(iw);
var scene = new Scene(root);
stage.setTitle("SepiaTone");
scene.setFill(Color.WHITESMOKE);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
当鼠标指针悬停在图像上时,该示例将 SepiaTone 效果应用于 Image。
var image = new Image("file:src/main/resources/mushroom.png");
var iw = new ImageView(image);
我们从磁盘加载一个 Image 并创建一个 ImageView 控件。
var sepia = new SepiaTone();
iw.effectProperty().bind(
Bindings.when(iw.hoverProperty())
.then((Effect) sepia)
.otherwise((Effect) null)
);
当鼠标指针位于 ImageView 控件的边界上时,设置 SepiaTone 效果。
iw.setCache(true); iw.setCacheHint(CacheHint.SPEED);
出于性能原因,缓存节点渲染。
JavaFX 透视变换
PerspectiveTransform 提供输入内容的非仿射变换。它通常用于在二维内容上创建三维效果。
package com.zetcode;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class PerspectiveEx extends Application {
private final int SIZE = 50;
@Override
public void start(Stage stage) {
initUI(stage);
}
private void initUI(Stage stage) {
var root = new StackPane();
var board = new Pane();
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
var r = new Rectangle(col * SIZE, row*SIZE,
SIZE, SIZE);
if ((col+row) % 2 == 0) {
r.setFill(Color.WHITE);
} else {
r.setFill(Color.BLACK);
}
board.getChildren().add(r);
}
}
var e = new PerspectiveTransform();
e.setUlx(30); // Upper-left point
e.setUly(170);
e.setUrx(370); // Upper-right point
e.setUry(170);
e.setLlx(0); // Lower-left point
e.setLly(300);
e.setLrx(400); // Lower-right point
e.setLry(300);
board.setEffect(e);
root.getChildren().add(board);
var scene = new Scene(root, Color.WHITESMOKE);
stage.setTitle("ChessBoard");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
该示例使用 PerspectiveTransform 效果形成一个棋盘格。
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
var r = new Rectangle(col * SIZE, row*SIZE,
SIZE, SIZE);
if ((col+row) % 2 == 0) {
r.setFill(Color.WHITE);
} else {
r.setFill(Color.BLACK);
}
board.getChildren().add(r);
}
}
此代码生成 64 个矩形。矩形具有黑色和白色。
var e = new PerspectiveTransform(); e.setUlx(30); // Upper-left point e.setUly(170); e.setUrx(370); // Upper-right point e.setUry(170); e.setLlx(0); // Lower-left point e.setLly(300); e.setLrx(400); // Lower-right point e.setLry(300); board.setEffect(e);
实例化一个 PerspectiveTransform 并将其应用于节点。我们提供四个角点的 x 和 y 坐标。这些点形成一个矩形,效果渲染到该矩形中。
JavaFX 组合效果
可以组合效果。如果已经设置了一个效果,setEffect 方法会替换它。要组合多个效果,我们使用 Effect 的 setInput 方法。
package com.zetcode;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.Light;
import javafx.scene.effect.Lighting;
import javafx.scene.effect.Reflection;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class CombiningEffectsEx extends Application {
@Override
public void start(Stage stage) {
initUI(stage);
}
private void initUI(Stage stage) {
var root = new StackPane();
Light.Distant light = new Light.Distant();
light.setAzimuth(50);
var lighting = new Lighting();
lighting.setLight(light);
lighting.setSurfaceScale(5);
var text = new Text();
text.setText("ZetCode");
text.setFill(Color.CADETBLUE);
text.setFont(Font.font(null, FontWeight.BOLD, 60));
var ref = new Reflection();
ref.setInput(lighting);
text.setEffect(ref);
root.getChildren().add(text);
var scene = new Scene(root, 300, 250, Color.WHITESMOKE);
stage.setTitle("Combining effects");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
该示例程序将 Reflection 效果与 Lighting 效果组合在 Text 节点上。
Light.Distant light = new Light.Distant(); light.setAzimuth(50); var lighting = new Lighting(); lighting.setLight(light); lighting.setSurfaceScale(5.0);
这些行创建了 Lighting 效果。
var text = new Text();
text.setText("ZetCode");
text.setFill(Color.CADETBLUE);
text.setFont(Font.font(null, FontWeight.BOLD, 60));
创建一个 Text 控件。字体被放大并加粗。文本的颜色是军校蓝。
var ref = new Reflection(); ref.setInput(lighting);
构造一个 Reflection 效果。它与使用 setInput 方法的照明效果相结合。
text.setEffect(ref);
最终的效果组合使用 setEffect 方法应用于节点。
在本章中,我们创建了几个视觉效果。