JavaFX 时间线播放滑块在异步时间点触发事件

JavaFX timeline playback slider firing events at asynchronous time points

我正在尝试实现一个自定义滑块,其上方有一个矩形条,线条代表特定时间点的事件,如下图所示。它基本上是滑块上方的时间轴,该事件被描绘为垂直线。

图中显示了滑块起点 (t=0) 和终点 (t=x) 之间的 14 条垂直线。每行对应一个带有一些上下文信息的任意事件。

滑块将实时播放,即拇指将以实时速度沿着其轨道移动。当滑块经过事件的指定时间时,它将在文本区域中打印事件的上下文信息。使用图表,当前显示的是事件发生在 14 秒时的信息。

问题: 1.如何让拇指实时移动? 2. 如何检测到拇指已到达事件并因此触发触发文本区域新输出的事件?

我的方法是处理所有事件并为每个事件创建一个计时器以在相关时间触发。这似乎很不雅观。并且将来会要求能够将拇指拖动到任何时间点,并且每次发生时都必须创建计时器事件,这似乎非常低效。

我正在使用 JavaFX,所以我想尽可能多地利用 属性 绑定。我在 Java 8 之前有很多经验,但这是我第一次在愤怒中使用 Java 8。

谢谢。

您可以使用 Timeline from the Animation API

简述:

public class TimelineEvent {
    private final Duration time ;
    private final String info ;
    public TimelineEvent(Duration time, String info) {
        this.time = time ;
        this.info = info ;
    }
    public Duration getTime() {
        return time ;
    }
    public String getInfo() {
        return info ;
    }
}

int maxSeconds = ... ;
TimelineEvent[] events = ... ; // populate array of events...
Slider slider = new Slider(0, maxSeconds, 0);
TextArea textArea = new TextArea();

// ...

Timeline timeline = new Timeline();
for (TimelineEvent event : events) {
    timeline.getKeyFrames().add(new KeyFrame(event.getTime(), 
        e -> textArea.setText(event.getInfo());
}

// make slider value change with timeline:
timeline.getKeyFrames().add(new KeyFrame(Duration.ZERO, 
    new KeyValue(slider.valueProperty(), 0)));
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(maxSeconds), 
    new KeyValue(slider.valueProperty(), maxSeconds)));

timeline.play();

如果用户要移动滑块 "by hand"(以及为其设置动画),另一种可能更方便的方法是使用动画来移动滑块,然后使用任一侦听器或滑块值的绑定:

int maxSeconds = ... ;
Slider slider = new Slider(0, maxSeconds, 0);
TextArea textArea = new TextArea();

Timeline timeline = new Timeline(
    new KeyFrame(Duration.ZERO, new KeyValue(slider.valueProperty(),0)),
    new KeyFrame(Duration.seconds(maxSeconds), new KeyValue(slider.valueProperty(),maxSeconds)));

textArea.textProperty().bind(Bindings.createStringBinding(
    () -> findInfoForTimepoint(slider.getValue()),
    slider.valueProperty()));

private String findInfoForTimepoint(double seconds) {
    // figure and return correct "info" for given time in seconds...
}