第二十一章《万年历》第3节:项目完整代码

本文介绍了一个使用Java Swing实现的万年历项目,该程序具备显示当前时间、切换时区、展示阳历节日等功能,并提供了详细的源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

万年历项目总共有3个类,这3个类的作用已在21.1.2小节中做过介绍,此处不再赘述,以下是这3个类的源代码,读者也能在本书提供的源代码文件夹中直接下载它们。

CalendarFrame.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Timer;
import java.util.TimerTask;
public class CalendarFrame extends JFrame{
    //内置资源
    //定义4个时区(北京、巴黎、纽约、悉尼)
    ZoneId[] zids = {
            ZoneId.of("Asia/Shanghai"),
            ZoneId.of("Europe/Paris"),
            ZoneId.of("America/Indianapolis"),
            ZoneId.of("Australia/Sydney")
    };
    //当前时区下标
    int zidIndex = 0;
    //定义当前时间
    ZonedDateTime curTime = ZonedDateTime.now(zids[zidIndex]);
    //格式化工具
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    //格式化当前时间形成的字符串
    String strCurTime;
    //定时器及定时器任务
    Timer timer;
    TimerTask task;
    //日历显示的年月(YearMonth)
    YearMonth shownYM;
    //阳历节日
    Festival[][] festivals= {
            {new Festival(1,1,"元旦")},
            {new Festival(2,14,"情人节")},
            {new Festival(3,8,"妇女节")},
            {new Festival(4,1,"愚人节")},
            {new Festival(5,1,"劳动节")},
            {new Festival(6,1,"儿童节")},
            {new Festival(7,1,"建党节")},
            {new Festival(8,1,"建军节")},
            {new Festival(9,10,"教师节")},
            {new Festival(10,1,"国庆节")},
            {new Festival(11,11,"光棍节")},
            {new Festival(12,25,"圣诞节")}
    };
    //区域1:当前时间区
    JLabel lblCTip;//当前日期指示时间标签
    JLabel lblCurTime;//当前日期显示时间标签
    JComboBox<String> jcbCities;//城市选择下拉框
    DefaultComboBoxModel<String> citiesData;//城市名称
    //区域2:日历显示年月
    JLabel lblShowTip;//桌面日历显示年月标签
    //区域3:日历主体部分
    JLabel[] lblweekDays = new JLabel[7];
    String[] strWeekDays = {"日","一","二","三","四","五","六"};
    JLabel[] lblDates = new JLabel[42];
    JLabel[] lblFestivals = new JLabel[42];
    //区域4:功能按钮
    JLabel lblSelectTip;//选择年月指示标签
    JComboBox<String> jcbYears;//年份选择下拉框
    DefaultComboBoxModel<String> yearsData;//年份
    JLabel lblYearTip;//年标签
    JButton btnCurYM;//回到当前月
    JButton btnPreYear;//前1年
    JButton btnNextYear;//后1年
    JButton btnPreMonth;//前1月
    JButton btnNextMonth;//后1月
    JComboBox<String> jcbMonths;//月份选择下拉框
    DefaultComboBoxModel<String> monthsData;//月份
    JLabel lblMonthTip;//月标签
    public CalendarFrame(){
        init();
    }
    private void init( ) {
        Container container = this.getContentPane();
        container.setLayout(null);
        //区域1
        //初始化当前时间指示标签
        lblCTip = new JLabel("当前时间");
        lblCTip.setSize(100, 25);
        lblCTip.setLocation(110, 30);
        lblCTip.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        //初始化城市选择下拉框
        citiesData = new DefaultComboBoxModel<String>();
        citiesData.addElement("北京");
        citiesData.addElement("巴黎");
        citiesData.addElement("纽约");
        citiesData.addElement("悉尼");
        jcbCities = new JComboBox<String>(citiesData);
        jcbCities.setSize(80, 25);
        jcbCities.setLocation(20, 30);
        jcbCities.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        jcbCities.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                zidIndex = jcbCities.getSelectedIndex();
                if(isCoincideCurDate(shownYM)==true){
                    resetYearMonth();
                }
                showCurTime();
            }
        });
        //初始化当前时间显示标签
        lblCurTime = new JLabel();
        lblCurTime.setSize(240, 25);
        lblCurTime.setLocation(200, 30);
        lblCurTime.setFont(new Font("微软雅黑", Font.PLAIN, 22));
        lblCurTime.setForeground(Color.BLUE);
        //区域2
        //初始化当前时间显示标签
        lblShowTip = new JLabel("日历显示年月:");
        lblShowTip.setSize(300, 25);
        lblShowTip.setLocation(20, 70);
        lblShowTip.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        //区域3:
        //排列周日到周六
        for(int i=0;i<7;i++){
            lblweekDays[i] = new JLabel();
            lblweekDays[i].setText(strWeekDays[i]);
            lblweekDays[i].setSize(60, 25);
            lblweekDays[i].setLocation(20+i*60, 100);
            lblweekDays[i].setFont(new Font("微软雅黑", Font.PLAIN, 22));
            container.add(lblweekDays[i]);
        }
        for(int i=0;i<42;i++){
            //排列日期标签组
            lblDates[i] = new JLabel();
            lblDates[i].setSize(60, 25);
            lblDates[i].setLocation(20+i%7*60, 130+i/7*50);
            lblDates[i].setFont(new Font("微软雅黑", Font.PLAIN, 20));
            //排列节日标签组
            lblFestivals[i] = new JLabel();
            lblFestivals[i].setSize(60, 25);
            lblFestivals[i].setLocation(20+i%7*60, 130+i/7*50+25);
            lblFestivals[i].setFont(new Font("微软雅黑", Font.PLAIN, 12));
            lblFestivals[i].setForeground(Color.RED);
            container.add(lblDates[i]);
            container.add(lblFestivals[i]);
        }
        //区域4
        //初始化选择年月指示标签
        lblSelectTip = new JLabel("跳转到");
        lblSelectTip.setSize(80, 25);
        lblSelectTip.setLocation(20, 450);
        lblSelectTip.setFont(new Font("微软雅黑", Font.PLAIN, 22));
        //初始化年份选择下拉框
        yearsData = new DefaultComboBoxModel<String>();
        jcbYears = new JComboBox<String>(yearsData);
        jcbYears.setSize(80, 25);
        jcbYears.setLocation(90, 450);
        jcbYears.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        jcbYears.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                getNewYearMonth();
            }
        });
        //初始化年标签
        lblYearTip = new JLabel("年");
        lblYearTip.setSize(20, 25);
        lblYearTip.setLocation(170, 450);
        lblYearTip.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        //初始化月份选择下拉框
        monthsData = new DefaultComboBoxModel<String>();
        jcbMonths = new JComboBox<String>(monthsData);
        jcbMonths.setSize(60, 25);
        jcbMonths.setLocation(200, 450);
        jcbMonths.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        //循环加入月份
        for (int i=1;i<=12;i++){
            monthsData.addElement(""+i);
        }
        jcbMonths.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                getNewYearMonth();
            }
        });
        //初始化月标签
        lblMonthTip = new JLabel("月");
        lblMonthTip.setSize(20, 25);
        lblMonthTip.setLocation(260, 450);
        lblMonthTip.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        //初始化回当前月按钮
        btnCurYM = new JButton("回当前月");
        btnCurYM.setSize(120, 25);
        btnCurYM.setLocation(300, 450);
        btnCurYM.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        btnCurYM.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                resetYearMonth();
            }
        });
        //初始化前1年按钮
        btnPreYear = new JButton("前1年");
        btnPreYear.setSize(100, 25);
        btnPreYear.setLocation(20, 490);
        btnPreYear.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        btnPreYear.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                plusYearMonth(-1,0);
            }
        });
        //初始化前1月按钮
        btnPreMonth = new JButton("前1月");
        btnPreMonth.setSize(100, 25);
        btnPreMonth.setLocation(120, 490);
        btnPreMonth.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        btnPreMonth.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                plusYearMonth(0,-1);
            }
        });
        //初始化后1月按钮
        btnNextMonth = new JButton("后1月");
        btnNextMonth.setSize(100, 25);
        btnNextMonth.setLocation(220, 490);
        btnNextMonth.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        btnNextMonth.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                plusYearMonth(0,1);
            }
        });
        //初始化后1年按钮
        btnNextYear = new JButton("后1年");
        btnNextYear.setSize(100, 25);
        btnNextYear.setLocation(320, 490);
        btnNextYear.setFont(new Font("微软雅黑", Font.PLAIN, 20));
        btnNextYear.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                plusYearMonth(1,0);
            }
        });
        container.add(lblCTip);
        container.add(jcbCities);
        container.add(lblCurTime);
        container.add(jcbYears);
        container.add(lblYearTip);
        container.add(jcbMonths);
        container.add(lblMonthTip);
        container.add(lblSelectTip);
        container.add(lblShowTip);
        container.add(btnPreYear);
        container.add(btnPreMonth);
        container.add(btnNextMonth);
        container.add(btnNextYear);
        container.add(btnCurYM);
        //初始化显示日历
        initCalendarComp();
        //启动时钟
        startClock();
        //显示日历
        showCalendar(shownYM);
    }
    //初始化日历及相关组件
    private void initCalendarComp(){
        //得到当前的年月
        shownYM = YearMonth.from(curTime);
        int year = shownYM.getYear();//得到年份数值
        int month = shownYM.getMonthValue();//得到月份数值
        int earliestYear = year-50;//earliestYear是当前年之前的50年
        //以循环方式加入101年
        for (int i=0;i<101;i++){
            yearsData.addElement((earliestYear+i)+"");
        }
        //定位被选中的年和月
        jcbYears.setSelectedIndex(50);
        jcbMonths.setSelectedIndex(month-1);
    }
    //显示当前时间
    private void showCurTime(){
        curTime = ZonedDateTime.now(zids[zidIndex]);//以某个时区为准获取当前时间
        strCurTime = formatter.format(curTime);//格式化当前时间
        lblCurTime.setText(strCurTime);//把当前时间显示到界面上
    }
    //启动时钟
    private void startClock(){
        timer = new Timer();//创建定时器
        task = new TimerTask() {//以匿名内部类的形式创建TimerTask的实现类对象
            @Override
            public void run() {
                showCurTime();
            }
        };
        timer.schedule(task,0,1000);//启动定时器并设置任务执行频率
    }
    //显示日历
    private void showCalendar(YearMonth ym){
        //清空日历
        clearCalendar();
        YearMonth lastYM = ym.minusMonths(1);//得到上个月
        int lastLen = lastYM.lengthOfMonth();//算出上个月有多少天
        LocalDate firstDay = ym.atDay(1);
        int weekDay = firstDay.getDayOfWeek().getValue();//本月1号是星期几
        int startIndex = weekDay;//本月第1天应该出现的位置
        if(weekDay==7){
            startIndex = 0;
        }
        int year = ym.getYear();
        int month = ym.getMonthValue();
        if(year<=0){
            year = year-1;
        }
        lblShowTip.setText("日历显示年月:"+year+"年"+month+"月");
        int startNum = lastLen-startIndex+1;
        int date = startNum;
        //打印上个月的最后几天
        int i=0;
        for(;i<startIndex;i++,date++){
            lblDates[i].setText(""+date);
            lblDates[i].setForeground(Color.LIGHT_GRAY);
        }
        date=1;
        int monthLen = ym.lengthOfMonth();//本月的最后一天
        boolean flag = isCoincideCurDate(ym);
        Festival[] monthFestival = festivals[month-1];
        for(;date<=monthLen;date++,i++){
            lblDates[i].setText(""+date);
            if(flag==true && date==curTime.getDayOfMonth()){//如果要打印的date表示今天
                lblDates[i].setForeground(Color.BLUE);//把今天显示为蓝色
            }
            for(int j=0;j<monthFestival.length;j++){
                if(monthFestival[j].getDay()==date){
                    lblFestivals[i].setText(monthFestival[j].getName());
                }
            }
        }
        int maxNum;
        if(startIndex+monthLen%7==0){
            maxNum = startIndex+monthLen;
        }else{
            maxNum = (startIndex+monthLen)/7*7+7;
        }
        date=1;//设置下个月被打印日期的开始
        //打印下个月的前几天
        for(;i<maxNum;i++,date++){
            lblDates[i].setText(""+date);
            lblDates[i].setForeground(Color.LIGHT_GRAY);
        }
    }
    //判断参数指定的年月与当前年月是否一致
    private boolean isCoincideCurDate(YearMonth ym){
        boolean flag = true;
        if(curTime.getYear()!=ym.getYear() || curTime.getMonthValue()!=ym.getMonthValue()){
            flag = false;
        }
        return flag;
    }
    //更新到当前年和月
    private void resetYearMonth(){
        curTime = ZonedDateTime.now(zids[zidIndex]);
        shownYM = YearMonth.from(curTime);
        showCalendar(shownYM);
    }
    //清空日历痕迹
    private void clearCalendar(){
        for(int i=0;i<lblDates.length;i++){
            lblDates[i].setText("");
            lblDates[i].setForeground(Color.BLACK);
            lblFestivals[i].setText("");
        }
    }
    //获得新的年和月
    private void getNewYearMonth(){
        int year = Integer.parseInt((String)jcbYears.getSelectedItem());
        int month = Integer.parseInt((String)jcbMonths.getSelectedItem());
        shownYM = YearMonth.of(year,month);
        showCalendar(shownYM);
    }
    //增加年月
    private void plusYearMonth(int year,int month){
        shownYM = shownYM.plusYears(year);
        shownYM = shownYM.plusMonths(month);
        showCalendar(shownYM);
    }
}

Festival.java

public class Festival {
    private int month;//节日所在月
    private int day;//节日所在日
    private String name;//节日名称
    public Festival(int month,int day,String name){
        this.month = month;
        this.day = day;
        this.name = name;
    }
    public int getMonth(){
        return this.month;
    }
    public int getDay(){
        return this.day;
    }
    public String getName(){
        return  this.name;
    }
}

MyCalendar.java

import javax.swing.*;
public class MyCalendar {
    public static  void main(String[] args){
        CalendarFrame calendarFrame = new CalendarFrame();
        calendarFrame.setSize(450, 600);
        calendarFrame.setLocationRelativeTo(null);
        calendarFrame.setTitle("万年历");
        calendarFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        calendarFrame.setVisible(true);
    }
}

除阅读文章外,各位小伙伴还可以点击这里观看我在本站的视频课程学习Java!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穆哥讲Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值