Last active
August 29, 2015 13:57
-
-
Save james-d/9686094 to your computer and use it in GitHub Desktop.
Java 8 Clock with convenient string bindings for "xxx ago" labels, with an example.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.LocalDateTime; | |
import java.time.format.DateTimeFormatter; | |
import java.time.format.FormatStyle; | |
import java.time.temporal.ChronoUnit; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.Optional; | |
import javafx.animation.Animation; | |
import javafx.animation.KeyFrame; | |
import javafx.animation.Timeline; | |
import javafx.beans.binding.Bindings; | |
import javafx.beans.binding.StringBinding; | |
import javafx.beans.property.ReadOnlyObjectProperty; | |
import javafx.beans.property.ReadOnlyObjectWrapper; | |
import javafx.util.Duration; | |
public class Clock { | |
private final ReadOnlyObjectWrapper<LocalDateTime> time ; | |
private final List<ChronoUnit> units = Arrays.asList( | |
ChronoUnit.MILLENNIA, | |
ChronoUnit.CENTURIES, | |
ChronoUnit.YEARS, | |
ChronoUnit.MONTHS, | |
ChronoUnit.WEEKS, | |
ChronoUnit.DAYS, | |
ChronoUnit.HOURS, | |
ChronoUnit.MINUTES, | |
ChronoUnit.SECONDS | |
); | |
private final Timeline clockwork ; | |
public Clock(Duration tickInterval, boolean start) { | |
time = new ReadOnlyObjectWrapper<>(LocalDateTime.now()); | |
clockwork = new Timeline(new KeyFrame(tickInterval, event -> time.set(LocalDateTime.now()))); | |
clockwork.setCycleCount(Animation.INDEFINITE); | |
if (start) { | |
clockwork.play(); | |
} | |
} | |
public Clock(Duration tickInterval) { | |
this(tickInterval, false); | |
} | |
public StringBinding getElapsedStringBinding(LocalDateTime start) { | |
return Bindings.createStringBinding(() -> | |
units.stream() | |
.filter(u -> start.plus(1, u).isBefore(time.get())) // ignore units where less than 1 unit has elapsed | |
.sorted(Comparator.reverseOrder()) // sort with biggest first | |
.findFirst() // get the first (biggest) unit | |
.map(u -> String.format("%d %s ago", u.between(start, time.get()), u)) // format as string | |
.orElse("Just now") // default if elapsed time is less than smallest unit | |
, time); | |
} | |
public StringBinding getElapsedStringBinding() { | |
return getElapsedStringBinding(LocalDateTime.now()); | |
} | |
public StringBinding getTimeStringBinding(DateTimeFormatter formatter) { | |
return Bindings.createStringBinding(() -> formatter.format(time.get()), time); | |
} | |
public StringBinding getTimeStringBinding() { | |
return getTimeStringBinding(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)); | |
} | |
public ReadOnlyObjectProperty<LocalDateTime> timeProperty() { | |
return time ; | |
} | |
public LocalDateTime getTime() { | |
return time.get(); | |
} | |
public void start() { | |
clockwork.play(); | |
} | |
public void stop() { | |
clockwork.stop(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javafx.application.Application; | |
import javafx.beans.binding.Bindings; | |
import javafx.geometry.Insets; | |
import javafx.geometry.Pos; | |
import javafx.scene.Scene; | |
import javafx.scene.control.Label; | |
import javafx.scene.control.ScrollPane; | |
import javafx.scene.control.TextField; | |
import javafx.scene.control.Tooltip; | |
import javafx.scene.layout.BorderPane; | |
import javafx.scene.layout.HBox; | |
import javafx.scene.layout.VBox; | |
import javafx.stage.Stage; | |
import javafx.util.Duration; | |
public class TimedItemDisplay extends Application { | |
@Override | |
public void start(Stage primaryStage) { | |
final Clock clock = new Clock(Duration.seconds(1), true); | |
final BorderPane root = new BorderPane(); | |
final HBox controls = new HBox(5); | |
controls.setAlignment(Pos.CENTER); | |
controls.setPadding(new Insets(10)); | |
final TextField itemField = new TextField(); | |
itemField.setTooltip(new Tooltip("Type an item and press Enter")); | |
controls.getChildren().add(itemField); | |
final VBox items = new VBox(5); | |
itemField.setOnAction(event -> { | |
String text = itemField.getText(); | |
Label label = new Label(); | |
label.textProperty().bind(Bindings.format("%s (%s)", text, clock.getElapsedStringBinding())); | |
items.getChildren().add(label); | |
itemField.setText(""); | |
}); | |
final ScrollPane scroller = new ScrollPane(); | |
scroller.setContent(items); | |
final Label currentTimeLabel = new Label(); | |
currentTimeLabel.textProperty().bind(Bindings.format("Current time: %s", clock.getTimeStringBinding())); | |
root.setTop(controls); | |
root.setCenter(scroller); | |
root.setBottom(currentTimeLabel); | |
Scene scene = new Scene(root, 600, 400); | |
primaryStage.setTitle("Timed item display"); | |
primaryStage.setScene(scene); | |
primaryStage.show(); | |
} | |
public static void main(String[] args) { | |
launch(args); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment