项目要求
根据生物节律曲线的定义,用户输入生日后,绘制生物节律曲线(使用JavaFX);能保存用户生日,并允许切换用户——即保存多个生日并进行切换。
解题思路描述:
- 首先设计输入出生年、月、日按钮和查询年、月下拉列表,实现基本的数据选择功能
- 其次设计选择用户下拉列表,能够选择三个不同的用户;设计切换用户按钮,单击后将当前年、月、日切换为该用户生日的年、月、日;设计保存按钮,单击后将当前的年、月、日设置为当前显示用户生日的年、月、日
- 最后编写绘制体力、情绪、智力节律曲线的方法;设计查询按钮,单击后出现显示曲线的场景
具体代码
首先奉上代码。
代码分为两个类,一个叫Birthday类,一个叫BioRhythmCalculator类。
Birthday类:
import javafx.scene.control.ComboBox;
public class Birthday {
public ComboBox<Integer> yearComboBox;
public ComboBox<Integer> monthComboBox;
public ComboBox<Integer> dayComboBox;
public Birthday(int year,int month,int day){
yearComboBox = new ComboBox<>();
monthComboBox = new ComboBox<>();
dayComboBox = new ComboBox<>();
yearComboBox.setValue(year);
monthComboBox.setValue(month);;
dayComboBox.setValue(day);
}
}
BioRhythmCalculator类:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class BioRhythmCalculator extends Application {
//初始化三个用户生日实例和一个当前显示的生日实例
public Birthday birthday = new Birthday(2000, 1, 1);
public Birthday User1 = new Birthday(2001, 2, 2);
public Birthday User2 = new Birthday(2002, 3, 3);
public Birthday User3 = new Birthday(2003, 10, 24);
//User记录当前是哪一个用户
public String User = "用户一";
public static void main(String[] args) {
launch(args);
}
// 下拉列表选项的年份
private Integer[] getYearOptions() {
return new Integer[]{2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010};
}
// 下拉列表选项的月份
private Integer[] getMonthOptions() {
return new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
}
// 下拉列表选项的日期
private Integer[] getDayOptions() {
return new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
}
// 绘制人体生物节律曲线的方法
private void drawBioRhythmCurve(long during1, long during2) {
//创建坐标轴
NumberAxis xAxis = new NumberAxis(during1, during2, 1);
NumberAxis yAxis = new NumberAxis(-1.0, 1.0, 0.2);
//创建线性图表
LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis);
//设置图表标题和轴标签
chart.setTitle("人体生物节律曲线");
xAxis.setLabel("天数");
yAxis.setLabel("节律值");
//创建身体节律数据系列
XYChart.Series<Number, Number> physicalSeries = new XYChart.Series<>();
physicalSeries.setName("身体节律");
//创建情感节律数据系列
XYChart.Series<Number, Number> emotionalSeries = new XYChart.Series<>();
emotionalSeries.setName("情感节律");
//创建智力节律数据系列
XYChart.Series<Number, Number> intellectualSeries = new XYChart.Series<>();
intellectualSeries.setName("智力节律");
//添加数据点到数据系列中
for (long i = during1; i <= during2; i++) {
double t = i;
double physicalValue = Math.sin(2 * Math.PI * t / 23);
double emotionalValue = Math.sin(2 * Math.PI * t / 28);
double intellectualValue = Math.sin(2 * Math.PI * t / 33);
physicalSeries.getData().add(new XYChart.Data<>(i, physicalValue));
emotionalSeries.getData().add(new XYChart.Data<>(i, emotionalValue));
intellectualSeries.getData().add(new XYChart.Data<>(i, intellectualValue));
}
// 将数据系列添加到图表中
chart.getData().addAll(physicalSeries, emotionalSeries, intellectualSeries);
// 创建布局并显示图表
VBox vbox = new VBox(chart);
Scene scene = new Scene(vbox, 800, 400);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("人体生物钟查询");
// 网格布局
GridPane grid = new GridPane();
grid.setPadding(new Insets(20, 20, 20, 20));
grid.setHgap(10);
grid.setVgap(10);
// 用户选择按钮
ComboBox<String> userComboBox = new ComboBox<>();
userComboBox.getItems().addAll("用户一", "用户二", "用户三");
userComboBox.setValue("用户一");
// 创建用户切换按钮
Button switchUserButton = new Button("切换用户");
switchUserButton.setOnAction(e -> {
String selectedUser = userComboBox.getValue();
User = selectedUser;
switch (selectedUser) {
case "用户一":
//当前显示的生日转换为用户一的生日
birthday.yearComboBox.setValue(User1.yearComboBox.getValue());
birthday.monthComboBox.setValue(User1.monthComboBox.getValue());
birthday.dayComboBox.setValue(User1.dayComboBox.getValue());
break;
case "用户二":
//当前显示的生日转换为用户二的生日
birthday.yearComboBox.setValue(User2.yearComboBox.getValue());
birthday.monthComboBox.setValue(User2.monthComboBox.getValue());
birthday.dayComboBox.setValue(User2.dayComboBox.getValue());
break;
case "用户三":
//当前显示的生日转换为用户三的生日
birthday.yearComboBox.setValue(User3.yearComboBox.getValue());
birthday.monthComboBox.setValue(User3.monthComboBox.getValue());
birthday.dayComboBox.setValue(User3.dayComboBox.getValue());
break;
}
});
// 注明每行的信息
Label birthDateLabel = new Label("请输入公历出生日期:");
Label queryMonthLabel = new Label("请输入查询月份:");
// 从这里输入出生日期 (年、月、日)
birthday.yearComboBox.getItems().addAll(getYearOptions());
birthday.monthComboBox.getItems().addAll(getMonthOptions());
birthday.dayComboBox.getItems().addAll(getDayOptions());
// 保存按钮
Button saveButton = new Button("保存");
saveButton.setOnAction(e -> {
switch (User) {
case "用户一":
User1.yearComboBox.setValue(birthday.yearComboBox.getValue());
User1.monthComboBox.setValue(birthday.monthComboBox.getValue());
User1.dayComboBox.setValue(birthday.dayComboBox.getValue());
break;
case "用户二":
User2.yearComboBox.setValue(birthday.yearComboBox.getValue());
User2.monthComboBox.setValue(birthday.monthComboBox.getValue());
User2.dayComboBox.setValue(birthday.dayComboBox.getValue());
break;
case "用户三":
User3.yearComboBox.setValue(birthday.yearComboBox.getValue());
User3.monthComboBox.setValue(birthday.monthComboBox.getValue());
User3.dayComboBox.setValue(birthday.dayComboBox.getValue());
break;
}
// 显示保存成功的提示对话框
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("提示");
alert.setHeaderText(null);
alert.setContentText( User + "生日保存成功!");
alert.showAndWait();
});
// 从这里输入要查询的年份
ComboBox<Integer> queryYearComboBox = new ComboBox<>();
queryYearComboBox.getItems().addAll(2023, 2024, 2025, 2026);
queryYearComboBox.setValue(2023);
// 从这里输入要查询的月份
ComboBox<Integer> queryMonthComboBox = new ComboBox<>();
queryMonthComboBox.getItems().addAll(getMonthOptions());
queryMonthComboBox.setValue(6);
// 查询按钮
Button submitButton = new Button("查询");
submitButton.setOnAction(e -> {
//获取用户选择的出生日期和查询年份
int birthYear = birthday.yearComboBox.getValue();
int birthMonth = birthday.monthComboBox.getValue();
int birthDay = birthday.dayComboBox.getValue();
int queryYear = queryYearComboBox.getValue();
int queryMonth = queryMonthComboBox.getValue();
//计算从当前生日到查询月份的第一天和最后一天之间的天数
LocalDate birthDate = LocalDate.of(birthYear, birthMonth, birthDay);
LocalDate queryFirstDay = LocalDate.of(queryYear, queryMonth, 1);
LocalDate queryLastDay = queryFirstDay.withDayOfMonth(queryFirstDay.lengthOfMonth());
long during1 = ChronoUnit.DAYS.between(birthDate, queryFirstDay);
long during2 = ChronoUnit.DAYS.between(birthDate, queryLastDay);
//绘制三条曲线
drawBioRhythmCurve(during1, during2);
});
// 将组件添加到网格中
grid.add(new Label("用户选择:"), 0, 0);
grid.add(userComboBox, 1, 0);
grid.add(switchUserButton, 3, 0);
grid.add(birthDateLabel, 0, 1);
grid.add(birthday.yearComboBox, 1, 1);
grid.add(new Label(" 年"), 2, 1);
grid.add(birthday.monthComboBox, 3, 1);
grid.add(new Label(" 月 "), 4, 1);
grid.add(birthday.dayComboBox, 5, 1);
grid.add(new Label(" 日 "), 6, 1);
grid.add(queryMonthLabel, 0, 2);
grid.add(queryYearComboBox, 1, 2);
grid.add(new Label(" 年 "), 2, 2);
grid.add(queryMonthComboBox, 3, 2);
grid.add(new Label(" 月 "), 4, 2);
grid.add(saveButton, 1, 3);
grid.add(submitButton, 3, 3, 6, 1);
Scene scene = new Scene(grid, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
接下来分别讲解上述各部分思路的实现。
第一部分的实现和调试:
设计下拉列表:
设计总的网格布局
设计标签和下拉列表
设计单击事件的处理程序
将组件添加到网络中
第一阶段效果图
每个下拉列表都有相应可供选择的标签,以“请输入公历出生日期”的“月”按钮为例:
以上是第一部分代码的效果。
第二部分的实现和调试
将日期设计为一个叫Birthday的类,方便创建实例
创建用户一、用户二、用户三和当前数据的生日实例,并用一个String记录当前是哪一个用户
新增用户选择按钮
设计用户切换按钮,单击后将当前显示的生日转换为该用户的生日
修改之前输入生日的部分代码
设计保存按钮,单击保存后就会将当前的生日保存到该用户的生日,单击后还会显示保存成果的窗口
修改之前的代码,添加进刚刚设计的按钮
第二部分效果展示
这是初始界面:
现在我们切换至用户三,并点击切换用户:
可以看到当前生日调整到了用户三的生日(默认设置的用户三生日)
接下来展示保存功能
首先将当前的生日改为2004年6月7日
然后单击保存:
为了验证是否真的保存了,我们先将用户切换为用户一:
接下来选择用户三,并单击切换用户:
可以看到和之前设置的生日一致,以上是第二阶段完成的效果。
第三部分的实现和调试:
进一步设计查询按钮,使用java.time.LocalDate类和java.time.temporal.ChronoUnit类,便利与日期有关的操作和计算,计算从当前生日到查询月份的第一天和最后一天之间的天数,并调用绘制曲线的方法
设计绘制曲线的方法,创建坐标轴,创建线性图表,设置图表标题和标签,常见身体节律、情感节律和智力节律数据系列,将数据系列添加到图表中,创建布局并显示图表
第三部分效果展示
用户选择用户三,单击切换用户,将查询月份选择2023年7月,单击查询,显示以下新窗口:
为了验证准确性,我找到了类似的人体生物钟查询网站,可以看到和该网站的图像一致。
将查询月份设置为2023年8月,单击查询,显示窗口如下:
同样与该网站绘制的图像一致。
//家人们点个赞再走吧