JavaFX 8 Changing the opacity of the stage does not work with StageStyle.TRANSPARENT (bug or my fault?)

我们两清 提交于 2019-12-12 04:53:14

问题


I'm trying to build a FadeIn/Out animation on a window (stage). If the mouse moves into the stage it should fade in and if the mouse leaves it should fade out.

I created a Timeline that modifies the stage.opacityProperty() to achieve this. I ran into problems when I set the stage style transparent like this stage.initStyle(StageStyle.TRANSPARENT);. If I do so, the fading will not be visible. The Timeline plays the animation, but the opacity change will not be rendered by JavaFX. When setting the stageStyle to default, everything works fine and the window plus its decoration will fade in and out.

I want this effect to work in TRANSPARENT stage style so i tried the following: I put a label onto the scene and change its textproperty in another Timeline. I now update the label text every 400msecs. If i do so, the opacity change will be rendered on every label-change.

This brings me to the conclusion, that modifying the opacity in TRANSPARENT stage style, will not result in a repaint of the stage. Modifying the label text will result in repaint. Does this mean, that i cannot fade a stage in TRANSPARENT stage style, if the content does not change?

Is this a bug or am I doing something wrong?

I've made an SSCCE that reproduces the problem. If you remove the line stage.initStyle(StageStyle.TRANSPARENT); the fadeIn/out animation will run smoothly.

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();
        });
    }

}

I'm currtently working with

  • Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
  • Windows 7 x64 Professional

回答1:


With the help of the JavaFX developer team I was able to find a workaround for this problem. Using a custom linear interpolator that changes the scene's fill property and immediately change it back to its original value will cause a repaint on the stage. This is done by the "bugFixInterpolator" in the code below:

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();
    }

}


来源:https://stackoverflow.com/questions/27038749/javafx-8-changing-the-opacity-of-the-stage-does-not-work-with-stagestyle-transpa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!