Skip to content

Instantly share code, notes, and snippets.

@bitwalk123
Forked from jewelsea/Clock.java
Last active October 7, 2019 17:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bitwalk123/2914aee9c9e42077d2c2 to your computer and use it in GitHub Desktop.
Save bitwalk123/2914aee9c9e42077d2c2 to your computer and use it in GitHub Desktop.
Clock in JavaFX
package clock;
/*
Reference
https://gist.github.com/jewelsea/2658491
*/
import java.util.Calendar;
import java.util.GregorianCalendar;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
public class AnalogClock extends Group {
AnalogClock() {
final Circle face = new Circle(100, 100, 100);
face.setId("face");
final Line hourHand = new Line(0, 0, 0, -50);
hourHand.setTranslateX(100);
hourHand.setTranslateY(100);
hourHand.setId("hourHand");
final Line minuteHand = new Line(0, 0, 0, -75);
minuteHand.setTranslateX(100);
minuteHand.setTranslateY(100);
minuteHand.setId("minuteHand");
final Line secondHand = new Line(0, 15, 0, -88);
secondHand.setTranslateX(100);
secondHand.setTranslateY(100);
secondHand.setId("secondHand");
final Circle spindle = new Circle(100, 100, 5);
spindle.setId("spindle");
Group ticks = new Group();
for (int i = 0; i < 12; i++) {
Line tick = new Line(0, -83, 0, -93);
tick.setTranslateX(100);
tick.setTranslateY(100);
tick.getStyleClass().add("tick");
tick.getTransforms().add(new Rotate(i * (360 / 12)));
ticks.getChildren().add(tick);
}
this.getChildren().addAll(face, ticks, spindle, hourHand, minuteHand, secondHand);
// determine the starting time.
Calendar calendar = GregorianCalendar.getInstance();
final double seedSecondDegrees = calendar.get(Calendar.SECOND) * (360 / 60);
final double seedMinuteDegrees = (calendar.get(Calendar.MINUTE) + seedSecondDegrees / 360.0) * (360 / 60);
final double seedHourDegrees = (calendar.get(Calendar.HOUR) + seedMinuteDegrees / 360.0) * (360 / 12);
// define rotations to map the analogueClock to the current time.
final Rotate hourRotate = new Rotate(seedHourDegrees);
final Rotate minuteRotate = new Rotate(seedMinuteDegrees);
final Rotate secondRotate = new Rotate(seedSecondDegrees);
hourHand.getTransforms().add(hourRotate);
minuteHand.getTransforms().add(minuteRotate);
secondHand.getTransforms().add(secondRotate);
// the hour hand rotates twice a day.
final Timeline hourTime = new Timeline(
new KeyFrame(
Duration.hours(12),
new KeyValue(
hourRotate.angleProperty(),
360 + seedHourDegrees,
Interpolator.LINEAR
)
)
);
// the minute hand rotates once an hour.
final Timeline minuteTime = new Timeline(
new KeyFrame(
Duration.minutes(60),
new KeyValue(
minuteRotate.angleProperty(),
360 + seedMinuteDegrees,
Interpolator.LINEAR
)
)
);
// move second hand rotates once a minute.
final Timeline secondTime = new Timeline(
new KeyFrame(
Duration.seconds(60),
new KeyValue(
secondRotate.angleProperty(),
360 + seedSecondDegrees,
Interpolator.LINEAR
)
)
);
// time never ends.
hourTime.setCycleCount(Animation.INDEFINITE);
minuteTime.setCycleCount(Animation.INDEFINITE);
secondTime.setCycleCount(Animation.INDEFINITE);
// start the analogueClock.
secondTime.play();
minuteTime.play();
hourTime.play();
}
}
/*
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
*/
/*
Created on : 2015/09/13, 10:02:56
Author : bitwalk
*/
#display {
-fx-font-size: 24;
-fx-font-family: monospace;
-fx-text-fill: navy;
-fx-background-color: cornsilk;
-fx-background-radius: 10.0px;
-fx-border-radius: 10.0px;
-fx-border-color: chocolate;
-fx-border-width: 0.5px;
}
#menu {
-fx-font-size: 12;
}
.root {
-fx-background-color: white;
}
#face {
-fx-fill: white;
}
#hourHand {
-fx-stroke: darkslategray;
-fx-stroke-width: 4;
-fx-stroke-line-cap: round;
}
#minuteHand {
-fx-stroke: derive(darkslategray, -5%);
-fx-stroke-width: 3;
-fx-stroke-line-cap: round;
}
#secondHand {
-fx-stroke: derive(firebrick, -15%);
-fx-stroke-width: 2;
-fx-stroke-line-cap: round;
}
#spindle {
-fx-fill: derive(darkslategray, +5%);
}
.tick {
/* -fx-stroke: derive(darkgoldenrod, -15%);*/
-fx-stroke: gray;
-fx-stroke-width: 3;
-fx-stroke-line-cap: round;
}
package clock;
import java.io.IOException;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.image.Image;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/*
Reference:
http://stackoverflow.com/questions/13227809/displaying-changing-values-in-javafx-label
Original Author: jewelsea
http://stackoverflow.com/users/1155209/jewelsea
*/
public class Clock extends Application {
// application info
static protected String appName = "Clock";
static protected String appVer = "0.1";
static protected String appAuthor = "Keiichi Takahashi";
static protected String appYear = "2015";
// image
static Image icoApp = new Image("/clock/clock-128.png");
@Override
public void start(Stage stage) throws IOException {
AnalogClock clock = new AnalogClock();
// popup menu
ContextMenu popup = new ContextMenu();
// popup -> Exit
MenuItem itemExit = new MenuItem("E_xit");
itemExit.setMnemonicParsing(true);
itemExit.setOnAction((ActionEvent t) -> {
System.exit(0);
});
popup.getItems().addAll(itemExit);
popup.setId("menu");
clock.setOnMouseClicked((MouseEvent event) -> {
// display popup when clicking right mouse button
if (event.getButton() == MouseButton.SECONDARY) {
popup.show(clock, event.getScreenX(), event.getScreenY());
}
});
VBox container = new VBox();
container.getChildren().add(clock);
container.setAlignment(Pos.CENTER);
Scene scene = new Scene(container, 200, 200);
scene.getStylesheets().add(getClass().getResource("clock.css").toExternalForm());
stage.setResizable(false);
stage.setTitle(appName);
stage.getIcons().add(icoApp);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
package clock;
import java.util.Calendar;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.util.Duration;
/**
*
* @author bitwalk
*/
class DigitalClock extends Label {
public DigitalClock() {
this.setAlignment(Pos.BASELINE_CENTER);
bindToTime();
}
// the digital clock updates once a second.
private void bindToTime() {
Timeline timeline;
timeline = new Timeline(
new KeyFrame(
Duration.seconds(0), (ActionEvent actionEvent) -> {
Calendar time;
String hourStr, minStr, secStr, ampmStr, dispTime;
time = Calendar.getInstance();
hourStr = StringUtilities.pad(2, ' ', time.get(Calendar.HOUR) == 0 ? "12" : time.get(Calendar.HOUR) + "");
minStr = StringUtilities.pad(2, '0', time.get(Calendar.MINUTE) + "");
secStr = StringUtilities.pad(2, '0', time.get(Calendar.SECOND) + "");
ampmStr = time.get(Calendar.AM_PM) == Calendar.AM ? "AM" : "PM";
dispTime = hourStr + ":" + minStr + ":" + secStr + " " + ampmStr;
this.setText(dispTime);
}),
new KeyFrame(Duration.seconds(1))
);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
}
package clock;
/**
*
* @author bitwalk
*/
class StringUtilities {
/**
* Creates a string left padded to the specified width with the supplied
* padding character.
*
* @param fieldWidth the length of the resultant padded string.
* @param padChar a character to use for padding the string.
* @param s the string to be padded.
* @return the padded string.
*/
public static String pad(int fieldWidth, char padChar, String s) {
StringBuilder sb = new StringBuilder();
for (int i = s.length(); i < fieldWidth; i++) {
sb.append(padChar);
}
sb.append(s);
return sb.toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment