JavaFX DatePickerSkin多日期高亮及按钮重复失效问题求助
JavaFX DatePicker高亮问题与按钮失效解决方案
需求
- 用户在文本框输入
dd/mm/yyyy格式的日期 - 点击按钮后,在同一个DatePickerSkin中显示选中日期,并高亮该日期及之前5天
遇到的问题
- 使用
dayCellFactory设置高亮样式始终不生效,怀疑默认主题覆盖或代码逻辑有误 - 未设置
dayCellFactory时按钮可多次点击生效,设置后仅能工作一次
用户代码片段
按钮点击事件代码
calculate_button.setOnAction(actionEvent -> { // 获取用户输入字符串 String user_date = textField_start_of_period.getText(); // 校验日期格式 String regex_check = "[0-9]{2}\\/[0-9]{2}\\/[0-9]{4}"; if (user_date.matches(regex_check)) { // 字符串转LocalDate DateTimeFormatter datetimeformatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); LocalDate localDate = LocalDate.parse(user_date, datetimeformatter); // 设置选中日期 today.setValue(localDate.plusDays(13)); // 存储需要高亮的日期 List<LocalDate> fertile_days = new ArrayList<>(); highlight_days.add(today.getValue().minusDays(5)); highlight_days.add(today.getValue().minusDays(4)); highlight_days.add(today.getValue().minusDays(3)); // 创建并设置dayCellFactory final Callback<DatePicker, DateCell> dayCellFactory = new Callback<>() { @Override public DateCell call(final DatePicker datePicker) { return new DateCell() { @Override public void updateItem(LocalDate item, boolean empty) { super.updateItem(item, empty); if (!empty && item != null) { if (highlight_days.contains(item)) { this.setStyle("-fx-background-color: pink"); } } } }; } }; today.setDayCellFactory(dayCellFactory); } else { String errormessage = new String("error"); textField_start_of_period.setText(errormessage); } });
尝试过的其他代码
- 直接指定集合日期:
highlight_days.add(LocalDate.now().minusDays(5)); highlight_days.add(LocalDate.of(2024,Month.JANUARY,5));
- 直接设置dayCellFactory+CSS:
today.setDayCellFactory(new Callback<DatePicker, DateCell>() { @Override public DateCell call(DatePicker param) { return new DateCell(){ @Override public void updateItem(LocalDate item, boolean empty) { super.updateItem(item, empty); if (!empty && item != null) { if(highlight.contains(item)) { this.setStyle("-fx-background-color: pink"); // 尝试添加样式类 // this.getStyleClass().add("hightlight_days"); } } } }; } });
CSS样式(src/main/resources/stylesheet.css)
.date-picker-popup > * > .date-cell.highlight_days { -fx-background-color: pink; }
DatePicker初始化代码
DatePicker today = new DatePicker(LocalDate.now()); DatePickerSkin datePickerSkin = new DatePickerSkin(today); Node popupContent = datePickerSkin.getPopupContent();
问题分析与解决方案
1. 按钮仅能工作一次的原因
每次点击按钮都重新创建并设置dayCellFactory,但DatePicker的dayCellFactory设置后,内部DateCell会被缓存,重复设置会导致视图绑定异常;同时未清空旧的高亮日期集合,会导致逻辑混乱。
解决方法:
- 仅初始化一次
dayCellFactory,将高亮日期集合设为可变成员变量; - 点击按钮时仅更新集合数据,强制刷新DatePicker视图。
2. 样式不生效的原因
- 直接使用
setStyle时,DateCell默认选中/hover样式优先级更高; - 样式类名称拼写错误(代码中写为
hightlight_days,CSS中是highlight_days); - CSS选择器优先级不足,未正确覆盖默认样式。
修正后的完整代码
初始化与事件绑定
// 成员变量定义 private DatePicker today; private List<LocalDate> highlightDays = new ArrayList<>(); public void initialize() { // 初始化DatePicker today = new DatePicker(LocalDate.now()); DatePickerSkin datePickerSkin = new DatePickerSkin(today); Node popupContent = datePickerSkin.getPopupContent(); // 加载CSS样式 today.getStylesheets().add(getClass().getResource("/stylesheet.css").toExternalForm()); // 仅初始化一次dayCellFactory today.setDayCellFactory(param -> new DateCell() { @Override public void updateItem(LocalDate item, boolean empty) { super.updateItem(item, empty); // 清除旧样式,避免残留 this.getStyleClass().remove("highlight_days"); this.setStyle(""); if (!empty && item != null) { if (highlightDays.contains(item)) { this.getStyleClass().add("highlight_days"); } } } }); // 按钮点击事件 calculate_button.setOnAction(actionEvent -> { String userDate = textField_start_of_period.getText(); String regexCheck = "[0-9]{2}\\/[0-9]{2}\\/[0-9]{4}"; if (userDate.matches(regexCheck)) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); LocalDate inputDate = LocalDate.parse(userDate, formatter); LocalDate targetDate = inputDate.plusDays(13); today.setValue(targetDate); // 清空旧数据,添加目标日期及之前5天 highlightDays.clear(); for (int i = 0; i <= 5; i++) { highlightDays.add(targetDate.minusDays(i)); } // 强制刷新弹窗视图 today.show(); today.hide(); } else { textField_start_of_period.setText("error"); } }); }
修正后的CSS样式
/* 提高选择器优先级,覆盖默认样式 */ .date-picker-popup > .calendar-grid > .date-cell.highlight_days { -fx-background-color: pink !important; -fx-text-fill: black; } /* hover状态样式 */ .date-picker-popup > .calendar-grid > .date-cell.highlight_days:hover { -fx-background-color: lightpink; }
内容的提问来源于stack exchange,提问作者javanewbie
相关产品推荐
相关产品推荐

