万年历项目总共有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);
}
}