JCalendar中今日日期无法高亮的问题排查与修复请求
问题原因与修复方案
核心问题分析
- 时间戳匹配失败:你存储的作业日期被处理为
00:00:00的时间戳,但JCalendar传递给isSpecial方法的今日日期是包含当前时分秒的完整时间戳。Date.equals方法比较的是完整时间戳,导致两者不匹配,assignmentDates.contains(date)返回false,今日未被标记为特殊日期。 - 默认样式优先级覆盖:即使解决了时间戳问题,JCalendar默认的今日单元格样式(比如背景色)会优先绘制,可能覆盖你自定义的特殊日期高亮。
修复步骤
1. 修改isSpecial方法,按日期(年/月/日)匹配
替换原Evaluator类中的isSpecial方法,不再依赖Date.contains,而是直接比较年、月、日三个字段:
@Override public boolean isSpecial(Date date) { Calendar targetCal = Calendar.getInstance(); targetCal.setTime(date); for (Date assignDate : assignmentDates) { Calendar assignCal = Calendar.getInstance(); assignCal.setTime(assignDate); if (targetCal.get(Calendar.YEAR) == assignCal.get(Calendar.YEAR) && targetCal.get(Calendar.MONTH) == assignCal.get(Calendar.MONTH) && targetCal.get(Calendar.DAY_OF_MONTH) == assignCal.get(Calendar.DAY_OF_MONTH)) { return true; } } return false; }
2. 解决默认样式覆盖问题(二选一)
方案A:通过UIManager移除默认今日背景
在程序启动时添加以下配置,让默认今日背景透明,避免覆盖自定义高亮:
UIManager.put("Calendar.dayTodayBackground", new Color(0,0,0,0)); // 透明背景 UIManager.put("Calendar.dayTodayForeground", Color.BLACK); // 保留文字颜色
方案B:自定义DayChooser控制绘制顺序
重写DayChooser的paintDay方法,确保特殊日期的样式优先绘制:
static class CustomDayChooser extends com.toedter.calendar.DayChooser { public CustomDayChooser() { super(); } @Override protected void paintDay(Graphics g, int x, int y, int w, int h, Date day, boolean isSelected, boolean isToday, boolean isWeekend, boolean isFocused) { // 先检查是否为特殊日期,优先绘制 for (IDateEvaluator evaluator : getDateEvaluators()) { if (evaluator.isSpecial(day)) { g.setColor(evaluator.getSpecialBackroundColor()); g.fillRect(x, y, w, h); g.setColor(evaluator.getSpecialForegroundColor()); g.drawString(String.valueOf(getDayOfMonth(day)), x + w / 2 - 4, y + h / 2 + 5); return; } } // 非特殊日期执行默认绘制逻辑 super.paintDay(g, x, y, w, h, day, isSelected, isToday, isWeekend, isFocused); } }
然后在创建JCalendar时替换默认DayChooser:
JCalendar jc = new JCalendar(); jc.setDayChooser(new CustomDayChooser());
完整修复代码
整合所有修改后的完整代码如下:
import com.toedter.calendar.IDateEvaluator; import com.toedter.calendar.JCalendar; import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import javax.swing.JFrame; import javax.swing.UIManager; public class calendar { private static class Evaluator implements IDateEvaluator { private List<Date> assignmentDates = new ArrayList<>(); public void add(Date dates) { assignmentDates.add(dates); } public void remove(Date date) { assignmentDates.remove(date); } public void setDates(List<Date> dates) { assignmentDates.addAll(dates); } @Override public boolean isSpecial(Date date) { Calendar targetCal = Calendar.getInstance(); targetCal.setTime(date); for (Date assignDate : assignmentDates) { Calendar assignCal = Calendar.getInstance(); assignCal.setTime(assignDate); if (targetCal.get(Calendar.YEAR) == assignCal.get(Calendar.YEAR) && targetCal.get(Calendar.MONTH) == assignCal.get(Calendar.MONTH) && targetCal.get(Calendar.DAY_OF_MONTH) == assignCal.get(Calendar.DAY_OF_MONTH)) { return true; } } return false; } @Override public Color getSpecialForegroundColor() { return Color.WHITE; } @Override public String getSpecialTooltip() { return "Highlighted Event"; } @Override public boolean isInvalid(Date date) { return false; } @Override public Color getInvalidForegroundColor() { return null; } @Override public Color getInvalidBackroundColor() { return null; } @Override public String getInvalidTooltip() { return null; } @Override public Color getSpecialBackroundColor() { return Color.MAGENTA; } } static class CustomDayChooser extends com.toedter.calendar.DayChooser { public CustomDayChooser() { super(); } @Override protected void paintDay(Graphics g, int x, int y, int w, int h, Date day, boolean isSelected, boolean isToday, boolean isWeekend, boolean isFocused) { for (IDateEvaluator evaluator : getDateEvaluators()) { if (evaluator.isSpecial(day)) { g.setColor(evaluator.getSpecialBackroundColor()); g.fillRect(x, y, w, h); g.setColor(evaluator.getSpecialForegroundColor()); g.drawString(String.valueOf(getDayOfMonth(day)), x + w / 2 - 4, y + h / 2 + 5); return; } } super.paintDay(g, x, y, w, h, day, isSelected, isToday, isWeekend, isFocused); } } private void display() { List<Date> datesList = new ArrayList<>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { datesList.add(dateFormat.parse("2025-03-06")); datesList.add(dateFormat.parse("2025-03-24")); } catch (Exception ex) { ex.printStackTrace(); } JFrame f = new JFrame("Calendar"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JCalendar jc = new JCalendar(); jc.setDayChooser(new CustomDayChooser()); List<Date> dates = new ArrayList<>(); for (Date d : datesList) { dates.add(createDate(d)); } Evaluator evaluator = new Evaluator(); evaluator.setDates(dates); jc.getDayChooser().addDateEvaluator(evaluator); f.add(jc); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); jc.repaint(); } private Date createDate(Date d) { Calendar c = Calendar.getInstance(); c.setTime(d); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); return c.getTime(); } public static void main(String[] args) { try { UIManager.put("Calendar.dayTodayBackground", new Color(0,0,0,0)); UIManager.put("Calendar.dayTodayForeground", Color.BLACK); for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (Exception e) { e.printStackTrace(); } EventQueue.invokeLater(new calendar()::display); } }
内容的提问来源于stack exchange,提问作者luna
相关产品推荐
相关产品推荐

