您似乎在这里寻找两种完全不同的功能。首先,您希望在 DatePicker
中突出显示选定日期之前的五天;其次,您想将 DatePicker
使用的内部日历作为单独的控件来使用。此答案主要解决第一点问题(同时对第二点给出一点提示,但并未进行实际测试)。
此方法采用自定义 CSS 伪类来表示高亮状态。style.css
文件内容很简单:
.date-cell:fertile {
-fx-background-color: pink;
}
日期选择器的单元格只需根据单元格代表的日期相对于所选日期(即 value
)是否在合适的范围内来设置伪类状态。这意味着如果单元格代表的日期改变(这可以通过 updateItem(...)
方法常规方式完成)或所选项目改变(这可以通过监听器完成)时,都需更新此伪类状态。下面是一个基本的实现示例:
import javafx.application.Application;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class App extends Application {
@Override
public void start(Stage stage) {
DatePicker picker = new DatePicker();
final int precedingDays = 5;
picker.setDayCellFactory(p -> new DateCell() {
PseudoClass fertile = PseudoClass.getPseudoClass("fertile");
{
picker.valueProperty().addListener((obs) -> updateStyle(getItem()));
}
@Override
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
updateStyle(date);
}
private void updateStyle(LocalDate date) {
LocalDate selected = picker.getValue();
if (date == null || selected == null) {
pseudoClassStateChanged(fertile, false);
} else {
long days = ChronoUnit.DAYS.between(date, selected);
pseudoClassStateChanged(fertile, days > 0 && days < precedingDays);
}
}
});
BorderPane pane = new BorderPane(picker);
pane.setPadding(new Insets(60));
Scene scene = new Scene(pane);
stage.setScene(scene);
scene.getStylesheets().add(App.class.getResource("style.css").toExternalForm());
stage.setTitle("突出显示前五天的日期选择器");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
对于始终作为弹出窗口显示日历的需求,您可以尝试用以下代码替换原有的布局设置:
// 原始代码
// BorderPane root = new BorderPane(picker);
// 替换为以下代码
DatePickerSkin skin = new DatePickerSkin(picker);
BorderPane pane = new BorderPane(skin.getPopupContent());
但请注意,据我所知,这不是 API 支持的官方使用方式,可能在某些场景下存在兼容性风险。