代码:
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.判断闰年和月份天数
我们可以直接写出两个方法来判断。如下:
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~。这就是一个可更新的日历实现方法,多尝试、多思考,努力成为大佬!!!