上一篇
怎么用java做窗口日历
- 后端开发
- 2025-08-24
- 5
Java做窗口日历,可借助Swing库的JFrame搭建
窗口,结合Calendar类处理日期逻辑
基础框架搭建
-
导入依赖库
需引入Swing组件库与AWT布局管理器:import javax.swing.; // JFrame, JPanel等组件 import java.awt.; // 布局管理类如GridLayout import java.util.Calendar; // 日期计算核心类 import java.util.Date; // 处理当前时间戳
-
创建主窗口(JFrame)
继承JFrame
并设置基本属性:public class MyCalendar extends JFrame { public MyCalendar() { setTitle("Java窗口日历"); // 窗口标题 setSize(400, 300); // 宽高尺寸 setDefaultCloseOperation(EXIT_ON_CLOSE); // 关闭事件响应 setLocationRelativeTo(null); // 屏幕居中显示 initializeUI(); // 初始化用户界面 } }
-
添加主面板(JPanel)
使用双层嵌套布局实现结构化排版:外层采用BorderLayout
划分区域,内层用GridLayout(7,7)
构建表格形式的日期网格。private void initializeUI() { // 顶部标题栏 显示年月信息 JLabel titleLabel = new JLabel("", SwingConstants.CENTER); titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); add(titleLabel, BorderLayout.NORTH); // 中间主体 星期与日期表格 JPanel gridPanel = new JPanel(new GridLayout(7, 7)); // ...后续填充单元格内容... add(gridPanel, BorderLayout.CENTER); }
动态生成日历内容
关键算法实现
通过Calendar
类获取当前月份的数据结构:
// 初始化当月第一天对应的星期几(周日=1,周一=2...饱和六=7) int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); // 注意:Java中周日被视为一周的第1天! // 计算该月总天数(考虑闰年影响) int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
可视化渲染逻辑
-
首行标注星期名称
创建固定字符串数组存储中文星期标识:String[] weekdays = {"日", "一", "二", "三", "四", "五", "六"}; for (String dayName : weekdays) { JLabel label = new JLabel(dayName); gridPanel.add(label); }
-
填充空白占位符
若首日非周日(即索引>0),则在前几格插入空标签:for (int i = 0; i < firstDayOfWeek 1; i++) { gridPanel.add(new JLabel()); // 无文字的透明格子 }
-
逐日添加交互元素
循环生成带数字的按钮或标签,支持点击事件监听:for (int day = 1; day <= daysInMonth; day++) { final int finalDay = day; // 用于Lambda表达式捕获变量值 JButton btn = new JButton(String.valueOf(day)); btn.addActionListener(e -> System.out.println("选中日期:" + finalDay)); gridPanel.add(btn); }
高级特性扩展
功能模块 | 实现方式 | 作用效果 |
---|---|---|
实时时钟同步 | 结合Timer 定时器每秒刷新界面显示 |
动态更新时间信息 |
主题切换 | 通过修改UIManager默认属性改变整体配色方案 | 暗黑/明亮模式自由切换 |
节假日标记 | 根据预存的特殊日期列表高亮对应单元格 | 直观展示法定休息日 |
跨月导航 | 栏两侧添加“<”“>”按钮触发前后月份切换 | 快速浏览相邻月份日程安排 |
事件提醒绑定 | 右键菜单关联备忘录编辑框,允许用户为特定日期添加备注 | 增强个人事务管理能力 |
完整示例代码整合
import javax.swing.; import java.awt.; import java.util.Calendar; import java.util.Date; public class MyCalendar extends JFrame { private JLabel titleLabel; // 显示年月的大标题 private JPanel dayGrid; // 存放日期按钮的网格面板 private Calendar currentCal; // 当前操作的日历实例 public MyCalendar() { initComponents(); // 组件初始化入口 loadCurrentMonthData(); // 加载初始数据 } private void initComponents() { // ===== 整体布局配置 ===== setLayout(new BorderLayout()); setSize(500, 400); setVisible(true); // ===== 头部年份显示区 ===== titleLabel = new JLabel("", SwingConstants.CENTER); titleLabel.setFont(new Font("SansSerif", Font.PLAIN, 24)); add(titleLabel, BorderLayout.NORTH); // ===== 中央日历表格区 ===== dayGrid = new JPanel(new GridLayout(6, 7)); // 最多6行×7列足够容纳所有情况 add(dayGrid, BorderLayout.CENTER); // ===== 底部控制按钮区 ===== JPanel controlPane = new JPanel(); JButton preMonthBtn = new JButton("上个月"); JButton nextMonthBtn = new JButton("下个月"); controlPane.add(preMonthBtn); controlPane.add(nextMonthBtn); add(controlPane, BorderLayout.SOUTH); // ===== 事件监听绑定 ===== preMonthBtn.addActionListener(e -> navigateMonth(-1)); nextMonthBtn.addActionListener(e -> navigateMonth(1)); } private void loadCurrentMonthData() { currentCal = Calendar.getInstance(); updateTitle(); // 更新标题栏文本 renderDayCells(); // 重新绘制所有日期单元格 } private void updateTitle() { String pattern = "yyyy年MM月"; SimpleDateFormat formatter = new SimpleDateFormat(pattern); titleLabel.setText(formatter.format(currentCal.getTime())); } private void renderDayCells() { dayGrid.removeAll(); // 清空现有内容 int startPos = currentCal.get(Calendar.DAY_OF_WEEK) 1; // 转换为0基索引 int totalDays = currentCal.getActualMaximum(Calendar.DAY_OF_MONTH); // 添加星期表头 String[] weekdayNames = {"日", "一", "二", "三", "四", "五", "六"}; for (String name : weekdayNames) { JLabel header = new JLabel(name); header.setHorizontalAlignment(SwingConstants.CENTER); dayGrid.add(header); } // 前置空白填充(当月第一天不是周日时) for (int i = 0; i < startPos; i++) { dayGrid.add(new JLabel()); } // 正式日期项生成 for (int d = 1; d <= totalDays; d++) { JButton dayBtn = new JButton(String.valueOf(d)); dayBtn.setPreferredSize(new Dimension(40, 40)); // 统一按钮大小 final int finalDay = d; // 解决闭包变量捕获问题 dayBtn.addActionListener(ev -> selectedDateChanged(finalDay)); dayGrid.add(dayBtn); } revalidate(); // 通知容器重新布局组件 repaint(); // 强制重绘可视区域 } private void selectedDateChanged(int selectedDay) { System.out.printf("您选择了 %d号n", selectedDay); // TODO: 此处可扩展更多业务逻辑,如弹出详情对话框等 } private void navigateMonth(int offset) { currentCal.add(Calendar.MONTH, offset); // +1表示下个月,-1表示上个月 loadCurrentMonthData(); // 重新加载新月份的数据视图 } public static void main(String[] args) { SwingUtilities.invokeLater(() -> new MyCalendar()); // 确保EDT线程安全启动GUI程序 } }
FAQs
Q1: 为什么运行后看不到任何日期?
A: 检查是否遗漏了revalidate()
和repaint()
调用,这两个方法必须成对出现才能触发Swing组件树的重构与重绘流程,特别是在动态修改面板子元素后(如removeAll()
操作),必须显式通知布局管理器更新视图。
Q2: 如何让日历支持多语言显示?
A: 将硬编码的文字提取到资源文件中(如.properties
格式),利用ResourceBundle
类实现国际化适配,例如定义英文版资源文件CalendarEN.properties
为:weekdays=Sun,Mon,Tue,Wed,Thu,Fri,Sat
,运行时根据系统默认语言环境自动加载对应