label不能使用动画平滑地调整宽度大小

35g0bw71  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(253)

我写了一个javafx应用程序。
我想每10毫秒更新一次标签宽度,其中标签代表一个值。
一般来说,我成功地做到了这一点,但有一个问题:标签闪烁的小值,在相反的大值。
在我以前的作品中,我注意到progressbar控件具有平滑的大小调整动画。
所以,我想让它像progressbar一样工作(平滑)。
下面是解释问题的示例代码:

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class MainApplication extends Application {

    private static final String LABEL_STYLE = "-fx-font-weight: bold; -fx-border-style: solid; -fx-pref-height: 38; -fx-background-color: ";
    private static final double MAX_WIDTH = 760;
    private static final double MAX_VALUE = 60000;
    private static final double VALUE_PER_PIXEL_RATIO = MAX_VALUE / MAX_WIDTH;
    private static final int ANIMATION_DURATION = 9000;
    private static final int KEYFRAME_DURATION = 10;
    private static final int ANIMATION_CYCLES = ANIMATION_DURATION / KEYFRAME_DURATION;

    private final Label label_1 = new Label();
    private final Label label_2 = new Label();
    private final Label label_3 = new Label();

    @Override
    public void start(Stage primaryStage) {

        label_1.setStyle(LABEL_STYLE + " #4363d8; ");
        label_2.setStyle(LABEL_STYLE + " #ffe119; ");
        label_3.setStyle(LABEL_STYLE + " #3cb44b; ");

        VBox root = new VBox();
        root.setSpacing(10);
        root.setPadding(new Insets(40, 30, 30, 30));
        root.getChildren().addAll(label_1, label_2, label_3);
        root.getChildren().addAll(new Label("Label 1 : Good (Smooth)"),
                new Label("Label 2 : Acceptable"),
                new Label("Label 3 : Weak (Blinks)"));

        Scene scene = new Scene(root);

        primaryStage.setScene(scene);
        primaryStage.setWidth(800);
        primaryStage.setHeight(350);
        primaryStage.show();

        playAnimation();

    }

    private void playAnimation() {

        MyData myData_1 = new MyData(58000, ANIMATION_CYCLES, VALUE_PER_PIXEL_RATIO);
        MyData myData_2 = new MyData(20000, ANIMATION_CYCLES, VALUE_PER_PIXEL_RATIO);
        MyData myData_3 = new MyData(4000, ANIMATION_CYCLES, VALUE_PER_PIXEL_RATIO);

        final Timeline timeline = new Timeline();
        timeline.setCycleCount(ANIMATION_CYCLES);

        timeline.getKeyFrames().add(new KeyFrame(Duration.millis(KEYFRAME_DURATION), new EventHandler<ActionEvent>() {
            @Override public void handle(ActionEvent actionEvent) {

                label_1.setPrefWidth(myData_1.getCurrentWidth());
                label_2.setPrefWidth(myData_2.getCurrentWidth());
                label_3.setPrefWidth(myData_3.getCurrentWidth());
            }

        }));

        timeline.play();

        // Replay animation
        timeline.setOnFinished(event -> playAnimation());

    }

    public static void main(String[] args) {
        launch(args);
    }
}

class MyData  {

    private double currentValue;
    private double currentWidth;
    private double incrementStep;
    private static double VALUE_PER_PIXEL_RATIO;

    public MyData(int maxValue, double cycles, double ratio) {
        super();
        this.incrementStep = maxValue / cycles;
        VALUE_PER_PIXEL_RATIO = ratio;
    }

    public double getCurrentWidth() {
        currentWidth = currentValue / VALUE_PER_PIXEL_RATIO;
        currentValue += incrementStep;
        return currentWidth;
    }
}

谢谢。

nkhmeac6

nkhmeac61#

对我来说,它不会闪烁,在DebianLinux上使用JavaFX15,使用intel集成图形芯片。
你正在做大量的工作,以动画的标签自己。与其自己制作动画,不如让时间轴来进行插值:

private void animate(Label label,
                     double value) {

    Timeline timeline = new Timeline(
        1000 / 10,  // every 10 ms
        new KeyFrame(Duration.millis(58000 / value * animationDuration),
            new KeyValue(label.prefWidthProperty(), 800 - 60)));

    timeline.setCycleCount(Timeline.INDEFINITE);
    timeline.play();
}

private void playAnimation() {
    animate(label_1, 58000);
    animate(label_2, 20000);
    animate(label_3, 4000);
}

我不确定强制每秒100帧是否有用。javafx似乎非常擅长在不指定帧速率的情况下创建平滑动画:

private void animate(Label label,
                     double value) {

    Timeline timeline = new Timeline(
        new KeyFrame(Duration.millis(58000 / value * animationDuration),
            new KeyValue(label.prefWidthProperty(), 800 - 60)));

    timeline.setCycleCount(Timeline.INDEFINITE);
    timeline.play();
}

private void playAnimation() {
    animate(label_1, 58000);
    animate(label_2, 20000);
    animate(label_3, 4000);
}

相关问题