摘要:本文介绍了一个基于 Java Swing 开发的《南京风景农历节气智能日历系统》。项目不仅实现了基础的万年历功能(公历、农历、星期显示),还集成了二十四节气计算算法节日红显提醒以及风景图片随月份自动切换的联动功能。界面采用 JSplitPane 分栏布局,美观大方。文中详细讲解了日历网格的绘制逻辑、农历转换思路及 GUI 事件处理机制,并附带完整源码,适合 Java 初学者及课程设计参考。

一、 项目背景与需求

在 Java 课程设计中,日历是一个经典题目。但普通的日历功能过于单一,为了拿高分,本项目在基础功能上进行了三大创新

  1. 数据丰富化:除了公历,增加了农历日期二十四节气的显示。
  2. 视觉本地化:结合“南京”地域特色,右侧展示南京四季风光,且图片随月份自动轮播。
  3. 交互人性化:支持用户自定义上传图片替换默认风景。
二、 系统功能演示

(此处建议插入 1-2 张运行截图,展示左右分栏的效果)

  • 左侧日历区:显示当前月份,节日标红(如春节、国庆),节气标蓝(如立春、雨水)。
  • 右侧展示区:默认显示该月份的南京风景图,支持缩放适配。
  • 顶部导航栏:支持年份、月份的快速翻页切换。
三、 核心技术点

本项目主要运用了以下 Java 技术栈:

  • GUI 框架:Java Swing (JFrame, JPanel, JSplitPane, GridLayout)。
  • 时间处理java.time.LocalDate (JDK 8 新特性,处理日期逻辑更丝滑)。
  • 布局管理BorderLayout + GridLayout (实现日历的 6行7列 排版)。
  • 事件监听ActionListener (按钮点击), ComponentListener (窗口大小改变监听)。
四、 核心代码实现
1. 日历网格的绘制逻辑 (CalendarPanel.java)

这是最核心的部分。我们需要计算当月第一天是星期几,从而决定第一行前面要空几个格子。

private void refreshCalendar() {
    daysPanel.removeAll(); // 清空旧格子
    
    // 获取当月第一天
    LocalDate firstDay = LocalDate.of(currentDate.getYear(), currentDate.getMonthValue(), 1);
    // 计算第一天是星期几(Monday=1, Sunday=7)
    int startDayOfWeek = firstDay.getDayOfWeek().getValue();
    int lengthOfMonth = currentDate.lengthOfMonth();

    // 1. 填充前导空格(让日期对齐星期几)
    for (int i = 1; i < startDayOfWeek; i++) {
        daysPanel.add(new JLabel(""));
    }

    // 2. 循环填充日期格子
    for (int day = 1; day <= lengthOfMonth; day++) {
        LocalDate date = LocalDate.of(currentDate.getYear(), currentDate.getMonthValue(), day);
        
        // 获取节日、节气、农历信息
        String festival = FestivalData.getFestival(date);
        String term = SolarTerm.getSolarTerm(date.getYear(), date.getMonthValue(), day);
        
        // 使用 HTML 标签实现字体颜色控制(节日红、节气蓝)
        String labelText = "<html><div style='text-align:center;'>" + day;
        if (festival != null) {
            labelText += "<br><font color='red' size='3'>" + festival + "</font>";
        } else if (term != null) {
            labelText += "<br><font color='blue' size='3'>" + term + "</font>";
        }
        labelText += "</div></html>";
        
        JLabel dayLabel = new JLabel(labelText, SwingConstants.CENTER);
        dayLabel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
        daysPanel.add(dayLabel);
    }
    daysPanel.revalidate();
    daysPanel.repaint();
}
2. 图片与月份的联动 (ImagePanel.java)

为了实现“翻页日历时,图片跟着换”的效果,我们在 CalendarPanel 中持有 ImagePanel 的引用。

// 在 ImagePanel 中实现图片缩放逻辑
private void setImage(String path) {
    ImageIcon icon = new ImageIcon(path);
    // Image.SCALE_SMOOTH 保证图片缩放后的清晰度
    Image scaled = icon.getImage().getScaledInstance(
            getWidth(), getHeight(), Image.SCALE_SMOOTH
    );
    imageLabel.setIcon(new ImageIcon(scaled));
}

// 在 Controller (Main) 中绑定联动
calendarPanel.setImagePanel(imagePanel);
3. 二十四节气算法 (SolarTerm.java)

节气计算通常非常复杂,这里我们采用了一种基于年份系数的近似算法(寿星公式简化版),实现了无需联网即可计算节气。

// 节气计算核心片段
private static void generateTerms(int year) {
    double yearFactor = year - 2000;
    for (int i = 0; i < TERM_NAMES.length; i++) {
        // 估算公式
        double day = centuryTerm[i] + (0.2422 * yearFactor) - ((yearFactor) / 4);
        int month = (i / 2) + 1;
        // 存入缓存 Map
        termCache.put(year + "-" + month + "-" + (int)day, TERM_NAMES[i]);
    }
}
五、 遇到的问题与解决方案
  1. 问题:窗口缩放时,日历和图片的比例乱掉。
    • 解决:使用了 JSplitPane,并添加 ComponentListener 监听窗口大小变化,强制重置分割线位置为 0.6 (60%)。
  2. 问题:日历翻页时,第一行的日期对不齐。
    • 解决:利用 LocalDate.getDayOfWeek() 获取当月1号是星期几,前面添加对应数量的空 JLabel 占位。
六、 总结与源码下载

本系统完整实现了 Java Swing 的界面布局与事件处理,代码结构清晰(MVC分层思想),非常适合作为 Java 结课作业。

需要完整源码(包含所有 Java 类文件 + 图片素材 + 课程设计报告 Word):

  1. 关注博主 + 点赞本文;
  2. 在评论区留言 “求日历源码”;
  3. 或者直接私信我,看到必回!
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐