我试图在窗口(舞台)上构建FadeIn / Out动画。如果鼠标移动到舞台中,它应该淡入,如果鼠标离开,它应该淡出。
我创建了一个修改stage.opacityProperty()
的时间轴来实现这一目标。当我将舞台样式设置为透明时,我遇到了问题stage.initStyle(StageStyle.TRANSPARENT);
。如果我这样做,褪色将不可见。时间轴播放动画,但JavaFX不会呈现不透明度更改。将stageStyle设置为默认值时,一切正常,窗口及其装饰将淡入淡出。
我希望此效果在TRANSPARENT舞台风格中工作,所以我尝试了以下内容: 我在场景上放了一个标签,并在另一个时间轴中更改了它的textproperty。我现在每400毫秒更新标签文本。如果我这样做,将在每次标签更改时呈现不透明度变化。
这让我得出结论,修改TRANSPARENT舞台风格的不透明度,不会导致舞台重画。 修改标签文本将导致重新绘制。这是否意味着,如果内容没有改变,我不能在TRANSPARENT舞台风格中淡出舞台?
这是一个错误还是我做错了什么?
我制作了一个可以重现问题的SSCCE。如果删除行stage.initStyle(StageStyle.TRANSPARENT);
,则淡入/淡出动画将顺利运行。
package de.schuette.jfx.stage_opacity_bug;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class FadeApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
private Label label;
@Override
public void start(Stage stage) {
if (stage == null)
throw new IllegalArgumentException("No stage was set.");
this.label = new Label("HALLO WELT");
Scene scene = new Scene(label, 300, 300);
scene.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE) {
stage.close();
}
});
stage.setScene(scene);
stage.setOpacity(1);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setTitle("Opacity change does result in repaint when stage style is transparent.");
stage.setAlwaysOnTop(true);
stage.show();
Platform.runLater(() -> {
Timeline t = new Timeline(new KeyFrame(Duration.millis(0),
new KeyValue(stage.opacityProperty(), 1)), new KeyFrame(
Duration.millis(500), new KeyValue(stage.opacityProperty(),
0)));
t.setAutoReverse(true);
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
});
Platform.runLater(() -> {
Timeline t = new Timeline(new KeyFrame(Duration.millis(400), e -> {
label.textProperty().set(String.valueOf(Math.random()));
}));
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
});
}
}
我正在与
合作答案 0 :(得分:0)
在JavaFX开发团队的帮助下,我找到了解决此问题的方法。使用自定义线性插值器更改场景的填充属性并立即将其更改回原始值将导致舞台上的重新绘制。这是由" bugFixInterpolator"在下面的代码中:
package de.schuette.jfx.stage_opacity_bug;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class FadeApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
private Label label;
/*
* (non-Javadoc)
*
* @see javafx.application.Application#start(javafx.stage.Stage)
*/
@Override
public void start(Stage stage) {
if (stage == null)
throw new IllegalArgumentException("No stage was set.");
this.label = new Label("HELLO WORLD");
Scene scene = new Scene(label, 300, 300);
scene.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE) {
stage.close();
}
});
stage.setScene(scene);
stage.setOpacity(1);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setTitle("Opacity change does result in repaint when stage style is transparent.");
stage.setAlwaysOnTop(true);
stage.show();
Interpolator bugFixInterpolator = new Interpolator() {
@Override
protected double curve(double t) {
Paint fill = scene.getFill();
scene.setFill(Color.RED);
scene.setFill(fill);
return t;
}
@Override
public String toString() {
return "Interpolator.LINEAR";
}
};
Timeline t = new Timeline(new KeyFrame(Duration.millis(0),
new KeyValue(stage.opacityProperty(), 1, bugFixInterpolator)),
new KeyFrame(Duration.millis(500), new KeyValue(stage
.opacityProperty(), 0, bugFixInterpolator)));
t.setAutoReverse(true);
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
t = new Timeline(new KeyFrame(Duration.millis(400), e -> {
label.textProperty().set(String.valueOf(Math.random()));
}));
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
}
}