*15.32(控制时钟)
修改程序淸单14-21,在类中加入动画。添加两个方法 start() 和 stop() 以启动和停止时钟。编写一个程序,让用户使用 Start 和 Stop 按钮来控制时钟,如图15-36a所示
代码示例:编程练习题15_32ClockPane.java
package chapter_15;import java.util.Calendar;
import java.util.GregorianCalendar;import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
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.stage.Stage;
import javafx.util.Duration;public class 编程练习题15_32ClockPane extends Application{@Overridepublic void start(Stage primaryStage) throws Exception {ClockPane clock = new ClockPane();clock.setCurrentTime();HBox hBox = new HBox(5);Button btStart = new Button("Start");Button btStop = new Button("Stop");hBox.getChildren().addAll(btStart, btStop);hBox.setAlignment(Pos.CENTER);BorderPane borderPane = new BorderPane();borderPane.setCenter(clock);borderPane.setBottom(hBox);btStart.setOnMouseClicked(e ->{clock.start();});btStop.setOnMouseClicked(e ->{clock.stop();});Scene scene = new Scene(borderPane);primaryStage.setTitle("编程练习题15_32ClockPane");primaryStage.setScene(scene);primaryStage.show();}class ClockPane extends Pane{private int hour;private int minute;private int second;private double w = 250,h = 250;private EventHandler<ActionEvent> eventHandler = e -> setCurrentTime();private Timeline animation = new Timeline(new KeyFrame(Duration.millis(1000),eventHandler));public ClockPane() {setCurrentTime();animation.setCycleCount(Timeline.INDEFINITE);}public void stop() {animation.stop();}public void start() {animation.play();}public void setW(double w) {this.w = w;paintClock();}public void setH(double h) {this.h = h;paintClock();}public void setCurrentTime() {Calendar calendar = new GregorianCalendar();this.hour = calendar.get(Calendar.HOUR_OF_DAY);this.minute = calendar.get(Calendar.MINUTE);this.second = calendar.get(Calendar.SECOND);paintClock();}protected void paintClock() {double clockRadius = Math.min(w, h) * 0.8 * 0.5;double centerX = w / 2;double centerY = h / 2;Circle circle = new Circle(centerX, centerY, clockRadius);circle.setFill(Color.WHITE);circle.setStroke(Color.BLACK);double sLength = clockRadius * 0.8;double sencondX = centerX + sLength * Math.sin(second * (2*Math.PI/60));double sencondY = centerY - sLength * Math.cos(second * (2*Math.PI/60));Line sLine = new Line(centerX, centerY, sencondX, sencondY);sLine.setStroke(Color.RED);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);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);for(int i = -90;i < 270;i+=30) {double angle = Math.toRadians(i);double x = centerX-2 + (clockRadius-20) * Math.cos(angle); double y = centerY+3 + (clockRadius-20) * Math.sin(angle);double LineX = centerX-7 + (clockRadius-7) * Math.cos(angle); double LineY = centerY+4 + (clockRadius-7) * Math.sin(angle);int time = i/30+3;if(time == 0)time = 12;Text t = new Text(x,y,time+"");Text line = new Text(LineX,LineY,"—");line.setRotate(i);getChildren().add(t);getChildren().add(line);}for(int i = -90;i < 270;i+=6) {double angle = Math.toRadians(i);double LineX = centerX-3 + (clockRadius-3) * Math.cos(angle); double LineY = centerY+4.5 + (clockRadius-2.5) * Math.sin(angle);Text line = new Text(LineX,LineY,"-");line.setRotate(i);getChildren().add(line);}}
}
public static void main(String[] args) { Application.launch(args); }}
这段代码实现了一个简易的时钟界面,该时钟可以显示当前的时间,并且可以通过按钮来启动和停止时钟的更新。下面是代码的详细解释:
-
主类和启动方法:
- 类名为
编程练习题15_32ClockPane
,继承自Application
类。 start
方法用于启动JavaFX应用,并设置窗口、场景等。
- 类名为
-
内部类ClockPane:
ClockPane
类是一个自定义的Pane
,用于绘制时钟的各个部件。- 定义了一些成员变量,如
hour
、minute
、second
,用于存储当前的时间。 animation
是一个Timeline
对象,用于定时更新时钟的时间显示。
-
构造器:
- 构造器中初始化了
Timeline
动画,并设置了无限循环。
- 构造器中初始化了
-
方法说明:
setCurrentTime
: 获取当前系统时间,并更新成员变量hour
、minute
、second
。paintClock
: 清除Pane
上的内容,并重新绘制时钟。stop
: 停止Timeline
动画。start
: 启动Timeline
动画。
-
绘制时钟:
- 首先清除
Pane
上的所有内容。 - 绘制圆形背景
circle
,代表时钟的表盘。 - 绘制秒针
sLine
、分针mLine
和时针hLine
。- 秒针、分针和时针的位置是根据角度计算得出的,使用了三角函数。
- 角度转换为弧度,因为Java中的
Math.sin
和Math.cos
函数接受弧度值。 - 针的长度由
clockRadius
的百分比确定。
- 添加数字和刻度线:
- 每30度绘制一个较大的数字和对应的刻度线,表示小时。
- 每6度绘制一个小的刻度线,表示分钟。
- 首先清除
-
事件处理:
- 通过
EventHandler<ActionEvent>
接口定义了一个事件处理器eventHandler
,当动画的每一帧触发时会调用setCurrentTime
方法来更新时间。 btStart
和btStop
按钮用于启动和停止动画。
- 通过
-
场景设置:
- 使用
BorderPane
布局来组织时钟界面和按钮。 BorderPane
的中心区域放置ClockPane
,底部放置包含btStart
和btStop
按钮的HBox
。
- 使用
-
主方法:
- 调用
Application.launch(args)
启动JavaFX应用。
- 调用
这个程序实现了以下功能:
- 显示当前时间。
- 动态更新时间。
- 提供按钮来启动和停止时间更新。
- 时钟界面包括时针、分针、秒针、数字和刻度线。
运行这个程序时,会看到一个带有时钟和控制按钮的窗口。点击“Start”按钮后,时钟会动态更新显示的时间,点击“Stop”按钮则会停止更新。
结果展示