用Java实现日历记事本
1. 实验目的
掌握RandomAccessFile类的使用;掌握字符输入、输出流和缓冲输入、输出流的使用。
2. 实验要求
实验前,应事先熟悉相关知识点,拟出相应的实验操作步骤,明确实验目的和要求;实验过程中,服从实验指导教师安排,遵守实验室的各项规章制度,爱护实验仪器设备;实验操作完成后,认真书写实验报告,总结实验经验,分析实验过程中出现的问题。
3. 实验内容
编程实现日历记事本。具体要求如下:
(1)该日历可以通过在文本框中输入年份和月份设置日期,也可按年前后翻动,用鼠标左键单击“上年”和“下年”按钮,将当前日历的年份减一和加一。还可以在某年内按月前后翻动,用鼠标左键单击“上月”和“下月”按钮,将日历的月份减一和加一。
(2)左键单击日历上的日期,可以通过右侧的记事本(文本区)编辑有关日志,并将日志保存到一个文件,该文件的名字是由当前日期组成的字符序列。用户可以读取、删除某个日期的日志,也可以继续向某个日志添加新的内容。在保存、删除和读取日志时都会先弹出一个确认对话框,以确认保存、删除和读取操作。
(3)当某个日期有日志时,该日期以粗体16号字显示,表明这个日期有日志;当用户删除某个日期的日志后,该日期恢复原来的外观。
实现效果图(参考)如下:
提示:(1)组件调用public void setFont(Fontf)方法可以设置组件上的字体,Font类的构造方法为:public Font(Stringname,intstyle,intsize),其中name是字体的名字,style决定字体的样式(如Font.BOLD表示粗体)size决定字体的大小。(具体请参考JDK API)
(2)当左键单击日历上的日期时,如要获取该日期,可通过处理该组件上的鼠标事件来实现。
4. 实验步骤、实施过程、关键代码、实验结果及分析说明等
代码(半成品,没有添加监听事件):
package CalendarNote;
import java.awt.*;
import java.util.Calendar;
import java.io.*;
import javax.swing.*;
public class CalendarNotebook extends JFrame {
JButton prevYearBtn, nextYearBtn, prevMonthBtn, nextMonthBtn, saveBtn, deleteBtn, readBtn;
JTextField yearField, monthField, date;
JTextArea textArea;
JPanel northPanel, southPanel, leftPanel, rightPanel;
String clickDay;
Calendar ca = Calendar.getInstance();
public CalendarNotebook() {
//基本设置
setVisible(true);
//setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(400, 200); // 设置窗口位置
setSize(700, 500);
setLayout(new BorderLayout(10, 15)); // 东西南北中布局:水平间距(horizontal)10,垂直间距(vertical)15。
setResizable(false); // 窗口大小不可变
JPanel centerPanel = new JPanel(); // 创建一个中心面板
centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.X_AXIS)); // 设置中心面板的布局为盒子布局,横向排列
northPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10)); // 创建一个北部面板,使用流式布局,居中对齐,水平间距为15,垂直间距为10
southPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10)); // 创建一个南部面板,使用流式布局,居中对齐,水平间距为10,垂直间距为10
leftPanel = new JPanel(new GridLayout(7, 7)); // 创建一个左部面板,使用表格布局,7行7列
rightPanel = new JPanel(); // 创建一个右部面板
rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS)); // 设置右部面板的布局为盒子布局,纵向排列
Font font = new Font("黑体", Font.BOLD, 16); // 创建一个字体对象
yearField = new JTextField(6); // 创建一个文本框,设置初始宽度为6个字符
yearField.setPreferredSize(new Dimension(76, 26)); // 设置文本框的首选大小为宽度76,高度26
yearField.setText(String.valueOf(ca.get(Calendar.YEAR))); // 设置文本框的文本为当前年份(2023),ca.get(Calendar.YEAR):2023(java.lang.Integer)
yearField.setEditable(false); // 设置文本框不可编辑
yearField.setBackground(Color.white); // 设置文本框的背景颜色为白色
prevYearBtn = new JButton("上年"); // 创建一个“上年”按钮
prevYearBtn.setFont(font); // 设置“上年”按钮的字体为指定的字体
nextYearBtn = new JButton("下年"); // 创建一个“下年”按钮
nextYearBtn.setFont(font); // 设置“下年”按钮的字体为指定的字体
monthField = new JTextField(6); // 创建一个文本框,设置初始宽度为6个字符
monthField.setText(String.valueOf(ca.get(Calendar.MONTH) + 1)); // 设置文本框的文本为当前月份(加1是因为Calendar.MONTH返回的是0-11,需要加1转换为1-12)
monthField.setPreferredSize(new Dimension(76, 26)); // 设置文本框的首选大小为宽度76,高度26
monthField.setEditable(false); // 设置文本框不可编辑
monthField.setBackground(Color.white); // 设置文本框的背景颜色为白色
nextMonthBtn = new JButton("下月"); // 创建一个“下月”按钮
nextMonthBtn.setFont(font); // 设置“下月”按钮的字体为指定的字体
prevMonthBtn = new JButton("上月"); // 创建一个“上月”按钮
prevMonthBtn.setFont(font); // 设置“上月”按钮的字体为指定的字体
northPanel.add(prevYearBtn);
northPanel.add(yearField);
northPanel.add(nextYearBtn);
northPanel.add(prevMonthBtn);
northPanel.add(monthField);
northPanel.add(nextMonthBtn);
// 添加左边的日历面板
int today = ca.get(Calendar.DAY_OF_MONTH); // 获取当前日期的天数
clickDay = String.valueOf(today); // 将当前日期的天数转换为字符串
week(); // 调用week方法
Day(); // 调用Day方法
centerPanel.add(leftPanel); // 将左部面板添加到中心面板
// 创建一个用于间隔的空面板
JPanel splitPanel = new JPanel(); // 创建一个面板作为间隔
splitPanel.setPreferredSize(new Dimension(10, 10)); // 设置间隔面板的首选大小为宽度10,高度10
centerPanel.add(splitPanel); // 将间隔面板添加到中心面板
date = new JTextField(10); // 创建一个文本框用于显示日期
date.setFont(font); // 设置文本框的字体
date.setHorizontalAlignment(JTextField.CENTER); // 设置文本在文本框中的水平对齐方式为居中
date.setPreferredSize(new Dimension(10, 10));// 设置文本框的首选大小为宽度10,高度10
date.setEditable(false); // 设置文本框不可编辑
date.setText("日历:" + ca.get(Calendar.YEAR) + "年" + (ca.get(Calendar.MONTH) + 1) + "月" + today + "日"); // 设置文本框的文本为当前日期
textArea = new JTextArea(15, 20); // 创建一个文本域,并设置行数和列数
textArea.setFont(new Font("黑体", Font.PLAIN, 16)); // 设置文本域的字体
textArea.setLineWrap(true); // 激活自动换行功能
textArea.setWrapStyleWord(true); // 激活断行不断字功能
JScrollPane scrollPane = new JScrollPane(textArea); // 创建一个滚动窗格,并将文本域放入其中
rightPanel.add(date); // 将日期文本框添加到右部面板
rightPanel.add(scrollPane); // 将滚动窗格添加到右部面板
centerPanel.add(rightPanel); // 将右部面板添加到中心面板
saveBtn = new JButton("保存日志");
saveBtn.setFont(font);
deleteBtn = new JButton("删除日志");
deleteBtn.setFont(font);
readBtn = new JButton("读取日志");
readBtn.setFont(font);
southPanel.add(saveBtn);
southPanel.add(deleteBtn);
southPanel.add(readBtn);
add(northPanel, BorderLayout.NORTH); // 将northPanel添加到布局的北部
add(centerPanel, BorderLayout.CENTER); // 将centerPanel添加到布局的中间
add(southPanel, BorderLayout.SOUTH); // 将southPanel添加到布局的南部
}
public void week() {
JButton lab1 = new JButton("一");
JButton lab2 = new JButton("二");
JButton lab3 = new JButton("三");
JButton lab4 = new JButton("四");
JButton lab5 = new JButton("五");
JButton lab6 = new JButton("六");
JButton lab7 = new JButton("日");
Font font = new Font("黑体", Font.BOLD, 16);
lab1.setFont(font);
lab2.setFont(font);
lab3.setFont(font);
lab4.setFont(font);
lab5.setFont(font);
lab6.setFont(font);
lab7.setFont(font);
leftPanel.add(lab7);
leftPanel.add(lab1);
leftPanel.add(lab2);
leftPanel.add(lab3);
leftPanel.add(lab4);
leftPanel.add(lab5);
leftPanel.add(lab6);
}
public void Day() {
int temp = 1; // 初始化临时变量temp为1
// 获取当前月份的最大天数
int Month_max = ca.getActualMaximum(Calendar.DATE); // getActualMaximum():表示根据传入的字段参数获取该字段意义下的最大值
ca.set(Calendar.DATE, 1);// 将日期设置为第一天
int Week = ca.get(Calendar.DAY_OF_WEEK);// 获取当前月份第一天是星期几
Font font = new Font("TimesRoman", Font.PLAIN, 16);// 创建字体对象
for (int i = 1; i <= 42; i++) {// 遍历42次,即遍历整个日历表格的所有格子
JButton b = new JButton();// 创建一个按钮
b.setBackground(Color.white);// 设置按钮的背景色为白色
b.setFont(font);// 设置按钮的字体
if (i >= Week && i < Week + Month_max) {// 如果i在本月的日期范围内
b.setText(Integer.toString(temp));// 设置按钮的文本为当前日期
if (hasLog(yearField.getText(), monthField.getText(), b.getText())) {// 如果该日期有日志记录
b.setFont(new Font("TimesRoman", Font.BOLD, 16));// 设置按钮的字体为粗体
} else {
b.setFont(font);
}
temp++;// 递增临时变量temp
}
leftPanel.add(b);// 继续下一次循环
}
}
private boolean hasLog(String year, String month, String day) {
File file = new File("F:\\日志\\" + year + "-" + month + "-" + day + ".txt"); // 构造日志文件路径
return file.exists();// 判断日志文件是否存在
}
//刷新日历
public void refreshCalendar() {
leftPanel.removeAll();// 移除左部面板中的所有组件
week();// 调用week()方法,重新生成星期行
Day();// 调用Day()方法,重新生成日期格子
leftPanel.revalidate();// 重新验证左部面板的布局
leftPanel.repaint();// 重绘左部面板
}
public static void main(String[] args) {
// 使用SwingUtilities的invokeLater方法,确保在事件分发线程(Event Dispatch Thread)中执行
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// 创建一个CalendarNotebook对象
new CalendarNotebook();
}
});
}
}
5.涉及知识点
setLocationRelativeTo()方法:设置相对定位
getActualMaximum():表示根据传入的字段参数获取该字段意义下的最大值
calendar.getinstance()获取的时间作用及相关细节解析