Reputation: 35
I'm attempting to implement a custom slider with a rectangular strip above it with lines representing events at certain points in time, as shown in the diagram below. It's basically a timeline above a slider, which event depicted as vertical lines.
The diagram shows 14 vertical lines in between the start (t=0) and end (t=x) of the slider. Each line corresponds an arbitrary event with some contextual information.
The slider will play in real-time, i.e. the thumb will move along its track at a real-time pace. When the slider passes an event's specified time, it will print the event's contextual information in a text area. Using the diagram, the information for the event at 14 seconds is currently being shown.
QUESTIONS: 1. How do I make the thumb move in real-time? 2. How do I detect that the thumb has reached an event and therefore fire an event that triggers new output on the text area?
My approach would be to process all events and create a timer for each to fire at the associated time. This seems rather inelegant. And there will be a future requirement to be able to drag the thumb around to any point in time and having to create timer events everytime that occurs seems very inefficient.
I'm using JavaFX and so i would like to leverage the property binding as much as possible. I have tons of experience pre-Java 8 but this is the first time i'm using Java 8 in anger.
Thank you.
Upvotes: 1
Views: 931
Reputation: 209330
You can do this using a Timeline
from the Animation API.
In brief:
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();
An alternative, which might be more convenient if the user is to move the slider "by hand" (as well as animating it), would be just to use the animation to move the slider and then use either listeners or bindings on the slider's value:
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()));
with
private String findInfoForTimepoint(double seconds) {
// figure and return correct "info" for given time in seconds...
}
Upvotes: 1