4

我有一个应用程序,它有一个带有一些双值的组合框。用户可以选择任何值。该应用程序附加了一个“ TimeLine ”,它将在控制台上打印一条语句。sscce在下面。应该发生的是应该打印从组合框中选择的选项的文本。请给个建议。

package just.to.test;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class TimerSample extends Application  {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Text Fonts");

        Group g = new Group();
        Scene scene = new Scene(g, 150, 100);

        ObservableList<Double> data = FXCollections.observableArrayList();

        data.add(5.0);
        data.add(10.0);
        data.add(15.0);
        data.add(20.0);

        ComboBox<Double> timeOptions = new ComboBox<Double>(data);
        timeOptions.getSelectionModel().selectFirst();

        g.getChildren().addAll(timeOptions);

        primaryStage.setScene(scene);
        primaryStage.show();

        final double timerInterval = timeOptions.getSelectionModel().getSelectedItem();

        KeyFrame keyFrame = new KeyFrame(Duration.seconds(timerInterval),
            new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    System.out.println("This is called every "
                        + timerInterval + " seconds");
                }
            });

        Timeline timerThread = new Timeline(keyFrame);
        timerThread.setCycleCount(Timeline.INDEFINITE);
        timerThread.play();
    }
}
4

2 回答 2

8

您不能将时间轴的持续时间绑定到属性,因为时间轴中关键帧的持续时间不是属性,您只能将属性绑定到属性。

相反,您需要做的是监听组合框值的变化,并在用户选择新持续时间时触发创建具有新持续时间的新关键帧。您也不能修改正在运行的时间线的关键帧,因此您必须在为时间线设置新的关键帧之前停止时间线,然后在设置新的关键帧后启动时间线。

示例代码

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.collections.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class TimerSample extends Application  {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {
        Group g = new Group();
        Scene scene = new Scene(g, 150, 100);

        ComboBox<Double> timerOptions = createTimerOptions(
                0.5, 1.0, 1.5, 2.0
        );
        g.getChildren().addAll(timerOptions);

        createTimer(timerOptions);

        stage.setScene(scene);
        stage.show();
    }

    private ComboBox<Double> createTimerOptions(double... options) {
        ObservableList<Double> data = FXCollections.observableArrayList();

        for (Double option: options) {
            data.add(option);
        }

        return new ComboBox<Double>(data);
    }

    private void createTimer(ComboBox<Double> timeOptions) {
        final Timeline timer = new Timeline();
        timer.setCycleCount(Timeline.INDEFINITE);

        timeOptions.valueProperty().addListener(new ChangeListener<Double>() {
            @Override
            public void changed(ObservableValue<? extends Double> observable, Double oldValue, Double newValue) {
                resetTimer(timer, newValue);
            }
        });

        timeOptions.getSelectionModel().selectFirst();
    }

    private void resetTimer(Timeline timer, final double timerInterval) {
        KeyFrame keyFrame = new KeyFrame(
            Duration.seconds(timerInterval),
            new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    System.out.println(
                            "This is called every "
                                    + timerInterval
                                    + " seconds"
                    );
                }
            }
        );

        timer.stop();
        timer.getKeyFrames().setAll(
                keyFrame
        );
        timer.play();
    }
}

只是想知道在性能方面是否会因为在组合框值的每次更改时添加一个新的关键帧而变得更重。

在这种情况下不要太担心性能 - 这是一种高效的操作。

除了创建新的关键帧之外没有其他解决方案,因为关键帧是不可变对象

您可以预先构造关键帧,或者在懒惰地构造它们时将它们放置在LRU 缓存中,但通常所涉及的额外复杂性几乎肯定不值得。

于 2013-10-23T20:44:54.230 回答
4

所有动画都有一个rateProperty()可以在运行动画上更改的!

这似乎是一个更清洁的解决方案:

private void createTimer(ComboBox<Double> timeOptions) {
    Timeline timer = new Timeline(
            new KeyFrame(Duration.seconds(1),
            evt-> System.out.println(
                        "This is called every "
                                + timeOptions.getValue()
                                + " seconds"
                ));

    timer.setCycleCount(Timeline.INDEFINITE);
    timer.rateProperty()
         .bind(new SimpleDoubleProperty(1.0)
         .divide(timeOptions.valueProperty()));

    timeOptions.getSelectionModel().selectFirst();
}
于 2017-06-22T18:29:23.477 回答