You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX DatePickerSkin多日期高亮及按钮重复失效问题求助

JavaFX DatePicker高亮问题与按钮失效解决方案

需求

  • 用户在文本框输入dd/mm/yyyy格式的日期
  • 点击按钮后,在同一个DatePickerSkin中显示选中日期,并高亮该日期及之前5天

遇到的问题

  1. 使用dayCellFactory设置高亮样式始终不生效,怀疑默认主题覆盖或代码逻辑有误
  2. 未设置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);
    }
});

尝试过的其他代码

  1. 直接指定集合日期:
highlight_days.add(LocalDate.now().minusDays(5));
highlight_days.add(LocalDate.of(2024,Month.JANUARY,5));
  1. 直接设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 02:25:00