我有一个使用 JavaFX 中的路径创建的自定义形状。我想从屏幕中心开始填充形状,在T秒内填满。
我目前有一个简单的版本,使用从底部填充的矩形,但我不知道如何将其应用于通用形状并从屏幕中心填充它。
这是我当前拥有的示例,其中颜色从形状的底部填充。 (红色箭头标记)
package com.example.javafx21;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.util.Duration;
public class HelloApplication extends Application {
@Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
StackPane stackPane = new StackPane();
stackPane.setLayoutX(50);
stackPane.setLayoutY(50);
Rectangle outlineRect = new Rectangle(100, 100);
outlineRect.setStroke(Color.BLACK);
outlineRect.setFill(Color.TRANSPARENT);
Rectangle fillRect = new Rectangle(100, 100);
fillRect.setFill(Color.BLUE);
Rectangle maskRect = new Rectangle(100, 100);
maskRect.setFill(Color.WHITE);
maskRect.yProperty().bind(fillRect.yProperty().add(fillRect.heightProperty()));
fillRect.setClip(maskRect);
stackPane.getChildren().addAll(fillRect, outlineRect);
Button button = new Button("Fill Rectangle");
button.setLayoutX(75);
button.setLayoutY(250);
pane.getChildren().addAll(stackPane, button);
TranslateTransition transition = new TranslateTransition(Duration.seconds(2), maskRect);
transition.setFromY(0);
transition.setFromX(0);
transition.setToY(-fillRect.getHeight());
// transition.setToX(-fillRect.getWidth());
transition.setCycleCount(1);
transition.setAutoReverse(false);
button.setOnAction(e -> transition.play());
pane.setOnMouseClicked(mouseEvent -> {
System.out.println("mouse X = " + mouseEvent.getX() + " Mouse Y = " + mouseEvent.getY());
});
Scene scene = new Scene(pane, 300, 300);
primaryStage.setTitle("Rectangle Fill Transition");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
考虑使用
LinearGradient
进行填充。给定要填充的矩形的一定比例 prop
,您可以在线性渐变中使用以下色标:
new Stop(0, Color.BLUE),
new Stop(prop, Color.BLUE),
new Stop(prop, Color.WHITE),
new Stop(1, Color.WHITE)
效果不会像这样创建“渐变”,而是在
BLUE
的值处从 WHITE
到 prop
的急剧过渡。因此,当 prop
为 0
时,矩形将全部为 WHITE
,而当 prop
为 1
时,矩形将全部为 BLUE
。
您可以根据要求进行对角填充,方法是制作
startX=1
、startY=1
、endX=0
、endY=0
并使用比例线性渐变。
最后,您需要对渐变进行动画处理。您可以通过将比例定义为
DoubleProperty
并使用 Timeline
对其值进行动画处理,然后使用 JavaFX 19 中引入的 map
方法将其值映射到适当的线性渐变来实现此目的。
这是全部内容:
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class HelloApplication extends Application {
@Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
StackPane stackPane = new StackPane();
stackPane.setLayoutX(50);
stackPane.setLayoutY(50);
Rectangle outlineRect = new Rectangle(100, 100);
outlineRect.setStroke(Color.BLACK);
outlineRect.setFill(Color.TRANSPARENT);
DoubleProperty fillProportion = new SimpleDoubleProperty(0);
Rectangle fillRect = new Rectangle(100, 100);
// fillRect.setFill(Color.BLUE);
fillRect.fillProperty().bind(fillProportion.map(prop ->
new LinearGradient(1, 1, 0, 0, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.BLUE),
new Stop(prop.doubleValue(), Color.BLUE),
new Stop(prop.doubleValue(), Color.WHITE),
new Stop(1, Color.WHITE)
)
));
// Rectangle maskRect = new Rectangle(100, 100);
// maskRect.setFill(Color.WHITE);
// maskRect.yProperty().bind(fillRect.yProperty().add(fillRect.heightProperty()));
// fillRect.setClip(maskRect);
stackPane.getChildren().addAll(fillRect, outlineRect);
Button button = new Button("Fill Rectangle");
button.setLayoutX(75);
button.setLayoutY(250);
pane.getChildren().addAll(stackPane, button);
// TranslateTransition transition = new TranslateTransition(Duration.seconds(2), maskRect);
// transition.setFromY(0);
// transition.setFromX(0);
// transition.setToY(-fillRect.getHeight());
//// transition.setToX(-fillRect.getWidth());
// transition.setCycleCount(1);
// transition.setAutoReverse(false);
Timeline transition = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(fillProportion, 0)),
new KeyFrame(Duration.seconds(2), new KeyValue(fillProportion, 1))
);
button.setOnAction(e -> transition.play());
pane.setOnMouseClicked(mouseEvent -> {
System.out.println("mouse X = " + mouseEvent.getX() + " Mouse Y = " + mouseEvent.getY());
});
Scene scene = new Scene(pane, 300, 300);
primaryStage.setTitle("Rectangle Fill Transition");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}