上一篇
Java做日历表可通过Date/Calendar类或LocalDate类获取日期信息,结合循环控制格式输出
是使用Java实现日历表的详细步骤和代码示例,涵盖核心逻辑、界面设计及功能扩展:
基础架构搭建
- 创建主窗口容器:基于Swing框架的
JFrame作为应用程序入口,设置合适尺寸(如600×400像素)并添加边框布局。new JFrame("Java日历程序")。 - 初始化表格组件:采用
JTable承载日期数据,默认7列对应周一至周日,通过DefaultTableModel动态管理行列内容,确保表头显示星期名称(可预设数组如[“日”,”一”,”二”,…])。 - 集成控制按钮:在底部面板放置“上个月”“下个月”“三个按钮,绑定动作监听器实现月份跳转逻辑。
日期计算核心算法
| 关键参数 | 获取方式 | 作用说明 |
|---|---|---|
| 当前年份 | calendar.get(Calendar.YEAR) |
确定所属年度范围 |
| 当月总天数 | 根据月份判断:普通月份取固定值,二月需结合闰年规则(能被4整除且非整百年或能被400整除) | 控制循环终止条件 |
| 首日星期索引 | calendar.get(Calendar.DAY_OF_WEEK) 1 |
定位起始位置偏移量 |
| 跨月补白处理 | 在首日前填充空字符串占位符 | 保持表格结构对齐 |
数据填充实现细节
- 模型重建机制:每次切换月份时清空旧模型,重新创建二维数组存储新数据,行数由最大可能周数决定(通常不超过6行)。
- 单元格渲染优化:自定义
TableCellRenderer实现特殊样式:周末背景高亮显示;节假日添加红色字体标记;鼠标悬停时增加边框效果。 - 异常边界处理:当某月最后一天位于非完整周时,自动填充无效日期占位符避免界面错乱。
交互功能增强
- 事件响应机制:为表格注册鼠标点击事件,解析选中单元格对应的具体日期对象,支持双击快速定位到指定日子的功能。
- 视图同步更新:点击导航按钮后立即刷新整个表格视图,同时更新标题栏显示的当前年月信息。
- 国际化适配:利用
Locale类加载不同语言环境的星期名称,提升多语言支持能力。
完整代码结构示例
import javax.swing.;
import java.awt.;
import java.util.;
import java.time.LocalDate; // Java 8及以上版本可用
public class CustomCalendar extends JFrame {
private JTable table;
private DefaultTableModel model;
private LocalDate currentDate = LocalDate.now();
public CustomCalendar() {
initUI();
updateCalendar();
}
private void initUI() {
setLayout(new BorderLayout());
String[] columnNames = {"日", "一", "二", "三", "四", "五", "六"};
model = new DefaultTableModel(columnNames, 0);
table = new JTable(model);
table.setRowHeight(40);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
JPanel btnPanel = new JPanel();
JButton preBtn = new JButton("←");
JButton nextBtn = new JButton("→");
JButton todayBtn = new JButton("quot;);
btnPanel.add(preBtn);
btnPanel.add(nextBtn);
btnPanel.add(todayBtn);
add(btnPanel, BorderLayout.SOUTH);
// 事件绑定
preBtn.addActionListener(e -> changeMonth(-1));
nextBtn.addActionListener(e -> changeMonth(1));
todayBtn.addActionListener(e -> goToToday());
}
private void updateCalendar() {
model.setRowCount(0); // 清空现有数据
LocalDate startOfMonth = currentDate.withDayOfMonth(1);
int daysInMonth = currentDate.lengthOfMonth();
int firstDayOfWeek = startOfMonth.getDayOfWeek().getValue(); // 1=周一...7=周日
// 构建二维数组填充数据
Object[][] data = new Object[6][7]; // 最多6周
int row = 0;
for (int i = 0; i < daysInMonth; i++) {
int col = (firstDayOfWeek + i 1) % 7;
int weekNum = (firstDayOfWeek + i 1) / 7;
data[weekNum][col] = i + 1; // 实际日期数值
}
// 将数组转换为表格行
for (Object[] week : data) {
model.addRow(week);
}
setTitle(currentDate.toString()); // 更新窗口标题显示当前月份
}
private void changeMonth(int offset) {
currentDate = currentDate.plusMonths(offset);
updateCalendar();
}
private void goToToday() {
currentDate = LocalDate.now();
updateCalendar();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new CustomCalendar().setVisible(true);
});
}
}
常见问题解答(FAQs)
Q1:如何处理不同地区的星期起始习惯?
A:可通过修改列名数组顺序实现,例如将“日”移到末尾即可适配以周一为首日的地区标准,同时调整算法中的取模运算逻辑。
Q2:为什么切换月份后表格高度会自动变化?
A:这是由于JTable默认根据内容自动调整行高,若需固定高度,可在初始化时调用table.setPreferredScrollableViewportSize(new Dimension(...))方法锁定尺寸。
该实现方案充分利用了Java标准库中的日期处理能力和Swing组件特性,通过模块化设计保证了代码的可维护性,开发者可根据实际需求进一步扩展功能,如添加事件提醒
