Java实现日历

代码:

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.*;

public class Calendar extends JFrame{
    private static final String[] WEEK={"星期一","星期二","星期三","星期四","星期五","星期六","星期日"};

    //当前日期
    private LocalDate currentDate=LocalDate.now();

    //年份和月份选择器
    private JComboBox<Integer> yearSelector;
    private JComboBox<Integer> monthSelector;

    //日历表格
    private JTable calTable;
    private DefaultTableModel tableModel;

    /**
     * 构造器,显示日历窗口
     */

    public Calendar(){
        this.setTitle("Calendar");
        this.setLayout(new BorderLayout());
        //创建年份月份选择器
        yearSelector=new JComboBox<>();
        for(int i=1900;i<=2100;i++){
            yearSelector.addItem(i);
        }
        yearSelector.setSelectedItem(currentDate.getYear());
        yearSelector.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                tableUpDate();
            }
        });
        monthSelector=new JComboBox<>();
        for(int i=1;i<=12;i++){
            monthSelector.addItem(i);
        }
        monthSelector.setSelectedItem(currentDate.getMonth().getValue());

        monthSelector.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                tableUpDate();
            }
        });

        //将选择器添加到面板上
        JPanel panel1=new JPanel(new FlowLayout());
        panel1.add(yearSelector);
        panel1.add(monthSelector);
        this.add(BorderLayout.NORTH,panel1);

        /**创建表格*/
        //设置表格不可编辑
        tableModel=new DefaultTableModel(6,7){
            public boolean isCellEditable(int row,int column){
                return false;
            }
        };

        tableModel.insertRow(0,WEEK);

        //设置表格基本属性
        calTable = new JTable(tableModel);
        calTable.setPreferredScrollableViewportSize(new Dimension(500, 250));
        calTable.setRowHeight(30);
        calTable.setGridColor(Color.BLACK);
        calTable.setSelectionBackground(new Color(175, 212, 255));
        calTable.setFont(new Font("黑体", Font.PLAIN, 16));
        calTable.setShowGrid(true);
        calTable.setCellSelectionEnabled(true);
        calTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        calTable.getTableHeader().setReorderingAllowed(false);
        JPanel panel2=new JPanel(new FlowLayout());
        panel2.add(calTable);
        this.add(panel2);
        JScrollPane scrollPane = new JScrollPane(calTable);
        this.add(scrollPane, BorderLayout.CENTER);
        this.pack();
        this.setLocationRelativeTo(null); // 居中显示
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        tableUpDate();
    }


    /**
     * 更新表格的方法
     * @param
     */

    public void tableUpDate(){
        //清空表格
        tableModel.setRowCount(0);
        //获取日期
        int month=monthSelector.getSelectedIndex()+1;
        int year=(int)yearSelector.getSelectedItem();


        // 获取该月的天数
        int daysInMonth = YearMonth.of(year, month).lengthOfMonth();


        // 获取该月第一天的星期几
        LocalDate firstDayOfMonth = LocalDate.of(year, month, 1);
        DayOfWeek firstDayOfWeek = firstDayOfMonth.getDayOfWeek();
        int offset = firstDayOfWeek.getValue();
        //System.out.println(firstDayOfWeek);


        //重绘表格
        tableModel.insertRow(0,WEEK);
        for(int i=0;i<6;i++) {
            tableModel.addRow(new Object[7]);
        }

        //向表格中添加日期
        int rowIndex=1;
        int dayIndex=offset-1;
        int tableIndex=offset;
        for(int i=1;i<=daysInMonth;i++,tableIndex++){
           // System.out.println(dayIndex);
            tableModel.setValueAt(i,rowIndex,dayIndex);
            dayIndex++;
            //自定义一个表格渲染器,对当前日期的单元格背景颜色进行修改
            DefaultTableCellRenderer ter=new DefaultTableCellRenderer(){
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
                    Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                    if (month == LocalDate.now().getMonthValue()&&value != null && value instanceof Integer && (Integer) value == currentDate.getDayOfMonth()) {
                        setBackground(Color.GRAY);
                    } else {
                        setBackground(null);
                    }
                    return c;
                }
            };
            calTable.getColumnModel().getColumn(tableIndex % 7).setCellRenderer(ter);
            if(tableIndex%7==0){
                rowIndex++;//换行
                dayIndex=0;//重置表格单元格索引
            }

        }
    }

    public static void main(String[] args){
        new Calendar();
    }
}

展示效果:

 通过展示效果可以看出来,这个日历UI主要通过表格(JTable)、下拉框(JComboBox)来实现的。

对于下拉框,我们可以创建两个下拉框组件并添加到面板上,调用addItem方法向其中添加日期。

对于日期,我们需要考虑两个方面:

  1. 判断该年是否为闰年,该月有几天?
  2. 判断该月的第一天是星期几?

1.判断闰年和月份天数

 我们可以直接写出两个方法来判断。如下:

 

public int getDaysInMonth(int year,int month){
        switch (month){
            case 2:
                return (isLeapYear(year)?29:28);
            case 4:
            case 6:
            case 9:
            case 11:
                return 30;
            default:
                return 31;
        }
    }

    public boolean isLeapYear(int year) {
        if((year%4==0&&year%100!=0)||year%400==0){
            return true;
        }
        return false;
    }

 2.判断该月的第一天是星期几

已知的一种计算方法:我们每个月的第一天是接着上个月的最后一天的,然后我们知道1900年的1月1日是星期一,那我们可以把从1900年到我们指定日期的前一个月的总天数求出来对7取余,就是上一个月最后一天的星期数(也是这个月开始前面的空格数)。

所以有如下:

 

public int getFirstDayOfWeek(int year,int month){
        int pastDays=0;
        for(int i=1900;i<year;i++){
            pastDays+=isLeapYear(i)?366:365;
        }
        for(int i=1;i<month;i++){
            pastDays+=getDaysInMonth(year,i);
        }
        return pastDays%7;

    }

看起来是不是非常简单呢。

3.如何让日历可更新

我们windows或者mac自带的日历都是可以看非当前月份的日历,所以才叫做万年历。那么我们该如何实现呢?

下拉框的作用是让我们选择日期,我们可以给下拉框组件添加事件监听,如果使用下拉框进行选择日期,则调用一个表格更新(tableUpDate)方法。

代码示例如下:

 public void tableUpDate(){
        //清空表格
        tableModel.setRowCount(0);
        //获取日期
        int month=monthSelector.getSelectedIndex()+1;
        int year=(int)yearSelector.getSelectedItem();


        // 获取该月的天数
        int daysInMonth = getDaysInMonth(year,month);


        // 获取该月第一天的星期几
        int offset=getFirstDayOfWeek(year,month)+1;


        //重绘表格
        tableModel.insertRow(0,WEEK);
        for(int i=0;i<6;i++) {
            tableModel.addRow(new Object[7]);
        }

        //向表格中添加日期
        int rowIndex=1;
        int dayIndex=offset-1;
        int tableIndex=offset;
        for(int i=1;i<=daysInMonth;i++,tableIndex++){
           // System.out.println(dayIndex);
            tableModel.setValueAt(i,rowIndex,dayIndex);
            dayIndex++;
            //自定义一个表格渲染器,对当前日期的单元格背景颜色进行修改
            DefaultTableCellRenderer ter=new DefaultTableCellRenderer(){
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
                    Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                    if (month == LocalDate.now().getMonthValue()&&value != null && value instanceof Integer && (Integer) value == currentDate.getDayOfMonth()) {
                        setBackground(Color.GRAY);
                    } else {
                        setBackground(null);
                    }
                    return c;
                }
            };
            calTable.getColumnModel().getColumn(tableIndex % 7).setCellRenderer(ter);
            if(tableIndex%7==0){
                rowIndex++;//换行
                dayIndex=0;//重置表格单元格索引
            }

        }
    }

 soga~。这就是一个可更新的日历实现方法,多尝试、多思考,努力成为大佬!!!

  • 6
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值