In: Computer Science
Modify the DetailedClockPane.java class in your detailed clock program, to add animation to this class. Be sure to include start() and stop() methods to start and stop the clock, respectively.Then write a program that lets the user control the clock with the start and stop buttons.
Since you have not provided the existing code, I’m using one from my old answers (previous versions of this question; assuming my guess is correct). In future, when you post questions like this, please don’t forget to include the existing code. Here is the modified code for DetailedClockPane.java and DetailedClockPaneTest.java files. Comments are included, go through it, learn how things work and let me know if you have any doubts or if you need anything to change. If you are satisfied with the solution, please rate the answer. Thanks
// DetailedClockPane.java
import java.util.Calendar;
import java.util.GregorianCalendar;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
public class DetailedClockPane extends Pane {
private int hour;
private int minute;
private int second;
//Timeline object for running the animation
private Timeline animationTimeline;
/**
* Construct a default clock with the current time
*/
public DetailedClockPane() {
//using current time
setCurrentTime();
// initializing timeline object to update time every second
animationTimeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> {
//updating seconds
second++;
//wrapping around fields if necessary
if (second > 59) {
second = 0;
minute++;
}
if (minute > 59) {
minute = 0;
hour++;
}
if (hour > 23) {
hour = 0;
}
//painting clock
paintClock();
}));
//setting cycle count to indefinite
animationTimeline.setCycleCount(Animation.INDEFINITE);
}
/**
* Construct a clock with specified hour, minute, and second
*/
public DetailedClockPane(int hr, int min, int sec) {
//assigning time
this.hour = hr;
this.minute = min;
this.second = sec;
// initializing timeline object to update time every second
animationTimeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> {
//updating seconds
second++;
//wrapping around fields if necessary
if (second > 59) {
second = 0;
minute++;
}
if (minute > 59) {
minute = 0;
hour++;
}
if (hour > 23) {
hour = 0;
}
//painting clock
paintClock();
}));
//setting cycle count to indefinite
animationTimeline.setCycleCount(Animation.INDEFINITE);
paintClock();
}
/**
* Return hour
*/
public int getHour() {
return hour;
}
/**
* Set a new hour
*/
public void setHour(int hour) {
this.hour = hour;
paintClock();
}
/**
* Return minute
*/
public int getMinute() {
return minute;
}
/**
* Set a new minute
*/
public void setMinute(int minute) {
this.minute = minute;
paintClock();
}
/**
* Return second
*/
public int getSecond() {
return second;
}
/**
* Set a new second
*/
public void setSecond(int second) {
this.second = second;
paintClock();
}
@Override
public void setWidth(double width) {
super.setWidth(width);
paintClock();
}
@Override
public void setHeight(double height) {
super.setHeight(height);
paintClock();
}
/* Set the current time for the clock */
public void setCurrentTime() {
// Construct a calendar for the current date and time
Calendar calendar = new GregorianCalendar();
// Set current hour, minute and second
this.hour = calendar.get(Calendar.HOUR_OF_DAY);
this.minute = calendar.get(Calendar.MINUTE);
this.second = calendar.get(Calendar.SECOND);
paintClock(); // Repaint the clock
}
/**
* Paint the clock
*/
private void paintClock() {
// Initialize clock parameters
double clockRadius = Math.min(getWidth(), getHeight()) * 0.8 * 0.5;
double centerX = getWidth() / 2;
double centerY = getHeight() / 2;
// Draw circle
Circle circle = new Circle(centerX, centerY, clockRadius);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
// Draw second hand
double sLength = clockRadius * 0.8;
double secondX = centerX + sLength * Math.sin(second * (2 * Math.PI / 60));
double secondY = centerY - sLength * Math.cos(second * (2 * Math.PI / 60));
Line sLine = new Line(centerX, centerY, secondX, secondY);
sLine.setStroke(Color.RED);
// Draw minute hand
double mLength = clockRadius * 0.65;
double xMinute = centerX + mLength * Math.sin(minute * (2 * Math.PI / 60));
double minuteY = centerY - mLength * Math.cos(minute * (2 * Math.PI / 60));
Line mLine = new Line(centerX, centerY, xMinute, minuteY);
mLine.setStroke(Color.BLUE);
// Draw hour hand
double hLength = clockRadius * 0.5;
double hourX = centerX + hLength * Math.sin((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
double hourY = centerY - hLength * Math.cos((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
Line hLine = new Line(centerX, centerY, hourX, hourY);
hLine.setStroke(Color.GREEN);
getChildren().clear();
getChildren().addAll(circle, sLine, mLine, hLine);
Group ticks = new Group();
Group numbers = new Group();
/**
* creating the big ticks (12)
*/
for (int i = 0; i < 12; i++) {
/*creating a line with a width of 10 and placing at 'clockRadius'
distance away from center*/
Line tick = new Line(0, clockRadius, 0, clockRadius - 10);
tick.setTranslateX(centerX);
tick.setTranslateY(centerY);
//applying proper rotation to rotate the tick
tick.getTransforms().add(new Rotate(i * (360 / 12)));
//adding to ticks group
ticks.getChildren().add(tick);
}
/**
* creating the small ticks (60)
*/
for (int i = 0; i < 60; i++) {
//lines will have a width of 5
Line tick = new Line(0, clockRadius, 0, clockRadius - 5);
tick.setTranslateX(centerX);
tick.setTranslateY(centerY);
tick.getTransforms().add(new Rotate(i * (360 / 60)));
ticks.getChildren().add(tick);
}
/**
* creating the numbers
*/
int num = 12; // starting with 12
for (int i = 0; i < 12; i++) {
//finding proper position x and y by applying the equation
double x = centerX + (clockRadius - 20) * Math.sin((i % 12) * (2 * Math.PI / 12));
double y = centerY - (clockRadius - 20) * Math.cos((i % 12) * (2 * Math.PI / 12));
//defining a text with hour label, (x-5 and y+5 are used to align text
//in proper position, considering font height & width)
Text t = new Text(x - 5, y + 5, "" + num);
numbers.getChildren().add(t);
num++;
if (num > 12) {
num = 1;
}
}
//adding ticks and numbers
getChildren().add(ticks);
getChildren().add(numbers);
}
//method to start the animation
public void start() {
animationTimeline.play();
}
//method to stop the animation
public void stop() {
animationTimeline.stop();
}
}
// DetailedClockPaneTest.java
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
public class DetailedClockPaneTest extends Application {
@Override
// Override the start method in the Application class
public void start(Stage primaryStage) {
// Creating a clock
DetailedClockPane clock = new DetailedClockPane();
//using a border pane, adding clock to center
BorderPane pane = new BorderPane();
pane.setCenter(clock);
//creating start button
Button start=new Button("start");
//adding event listener to start button to call start method of clock
start.setOnAction(e->clock.start());
//creating stop button and registering event listener
Button stop=new Button("stop");
stop.setOnAction(e->clock.stop());
//adding buttons to an HBox, setting spacing and alignment
HBox hbox=new HBox(start,stop);
hbox.setSpacing(20);
hbox.setAlignment(Pos.CENTER);
//adding hbox to bottom of pane
pane.setBottom(hbox);
//setting up and displaying a Scene
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("DetailedClockPane");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
/*OUTPUT*/