自定义javafx datepicker

时间:2017-09-25 10:58:36

标签: css javafx datepicker locale

如果我可以使用CSS或main.java/controller.java中的某些代码执行此操作,我试图避免使用自己的JavaFX控件。

datepicker中有一个按钮,显示一个calander图标,我想更改它以显示图像。 我可以使用-fx-graphic按钮来执行此操作。在datepicker中是否有等价物?

我还想知道工作日是否可以修改。我的Locale是中文,它显示"星期一","星期二"等等。这就像"工作日星期一",这是漫长而不必要的。我想将它改为一,二等。它相当于Mon,Tue等。

有没有这样做?如果CSS无法做到这一点。 可以使用反射和设置字符串值来完成吗?

2 个答案:

答案 0 :(得分:2)

在玩完日期选择器组件之后,我发现了如何仅使用css在日期选择器旁边的按钮中更改图标... 这更像是一个黑客,但我无法以“ 官方方式”在任何地方使用Google。

.date-picker:editable > .arrow-button > * {
    -fx-opacity: 0; /* Set the node in the button to be visible */
}

.date-picker > .arrow-button {
    -fx-background-image: url("/icons/calendar.png"); /* Url of the icon */
    -fx-background-size: 60% 60%; /* Can be `cover` or `100% 100%` ect. */
    -fx-background-repeat: no-repeat;
    -fx-background-position: center center; /* Put the icon in the center */
}

通过更多样式,我设法使日期选择器看起来像这样,请注意自定义图标:

enter image description here

答案 1 :(得分:2)

格式化/配置选择器的dropDown内部是在DatePickerContent中完成的。不幸的是,这是一个内部类(不知道为什么它没有进入公共api,fx9是将其连同皮肤一起移到公开位置的绝佳时机。)

DatePickerContent在方法updateDayNameCells()中配置weekDayName单元格的文本,该方法在需要重新配置时在内部被调用。如果允许您访问/调整内部代码内部:

  • 扩展DatePickerContent以覆盖updateDayNameCells,完全重新实现(c&p;)并使用您自己的格式化程序(以下示例使用“窄独立”样式)。必须以反射方式访问dayNameCells和其他字段(请注意:脏!)
  • 扩展DatePickerSkin并注入您的自定义内容,再次需要反射访问(请注意:脏!)
  • 扩展DatePicker并使其通过其皮肤工厂方法返回自定义皮肤

示例代码:

public class DatePickerConfig extends Application {

    /**
     * Custom picker content which allows to tweak the formatter for weekDay cells.
     */
    public static class XDatePickerContent extends DatePickerContent {

        private DateTimeFormatter weekDayNameFormatter;

        public XDatePickerContent(DatePicker datePicker) {
            super(datePicker);
        }

        /**
         * c&p from super to format with narrow formatter
         */
        @Override
        public void updateDayNameCells() {
            // first day of week, 1 = monday, 7 = sunday
            Locale locale = getLocale();
            int firstDayOfWeek = WeekFields.of(locale).getFirstDayOfWeek().getValue();

            List<DateCell> dayNameCells = getDayNameCells();
            int daysPerWeek = getDaysPerWeek();
            // july 13th 2009 is a Monday, so a firstDayOfWeek=1 must come out of the 13th
            LocalDate date = LocalDate.of(2009, 7, 12 + firstDayOfWeek);
            DateTimeFormatter weekDayNameFormatter = getWeekDayNameFormatter();
            for (int i = 0; i < daysPerWeek; i++) {
                String name = weekDayNameFormatter.withLocale(locale).format(date.plus(i, DAYS));
                dayNameCells.get(i).setText(getTitleCaseWord(name));
            }
        }

        /**
         * Lazily creates and returns the formatter for week days.
         * Note: this is called from the constructor which implies that
         * the field is not available.
         */
        private DateTimeFormatter getWeekDayNameFormatter() {
            if (weekDayNameFormatter == null) {
                weekDayNameFormatter =
                        createWeekDayNameFormatter(); // 
            }
            return weekDayNameFormatter;
        }

        /**
         * Factory method for weekDayNameFormatter, here: narrow standalone day name
         */
        protected DateTimeFormatter createWeekDayNameFormatter() {
            return DateTimeFormatter.ofPattern("ccccc");
        }

        // ------------- going dirty: reflective access to super

        protected String getTitleCaseWord(String str) {
            return (String) FXUtils.invokeGetMethodValue(DatePickerContent.class, this, "titleCaseWord", String.class, str);
        }

        protected int getDaysPerWeek() {
            return (int) FXUtils.invokeGetFieldValue(DatePickerContent.class, this, "daysPerWeek");
        }

        protected List<DateCell> getDayNameCells() {
            return (List<DateCell>) FXUtils.invokeGetFieldValue(DatePickerContent.class, this, "dayNameCells");
        }
    }

    /**
     * Custom picker skin that reflectively injects the custom content.
     */
    public static class XDatePickerSkin extends DatePickerSkin {

        public XDatePickerSkin(DatePicker control) {
            super(control);
        }

        /**
         * Overridden to reflectively inject the custom picker content.
         */
        @Override
        public Node getPopupContent() {
            DatePickerContent content = (XDatePickerContent) getDatePickerContent();
            if (!(content instanceof XDatePickerContent)) {
                content = new XDatePickerContent((DatePicker) getSkinnable());
                replaceDatePickerContent(content);
            }
            return content;
        }

        //------------- going dirty: reflective access to super

        protected DatePickerContent getDatePickerContent() {
            return (DatePickerContent) FXUtils.invokeGetFieldValue(DatePickerSkin.class, this, "datePickerContent");
        }

        protected void replaceDatePickerContent(DatePickerContent content) {
            FXUtils.invokeSetFieldValue(DatePickerSkin.class, this, "datePickerContent", content);
        }
    }

    private Parent createContent() {
        Locale.setDefault(Locale.CHINA);
        LocalDate now = LocalDate.now();
        DatePicker picker = new DatePicker(now) {

            @Override
            protected Skin<?> createDefaultSkin() {
                return new XDatePickerSkin(this);
            }

        };
        // just to see some options
        List<String> patterns = List.of("c", "ccc", "cccc", "ccccc", "e", "ee", "eee", "eeee", "eeeee");
        HBox box = new HBox(10);
        patterns.forEach(p -> {
            DateTimeFormatter ccc = DateTimeFormatter.ofPattern(p);
            String name = ccc.withLocale(getLocale()).format(now);
            box.getChildren().add(new Label(name));
        });

        BorderPane content = new BorderPane(picker);
        content.setBottom(box);
        return content;
    }

    protected Locale getLocale() {
        return Locale.getDefault(Locale.Category.FORMAT);
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent(), 400, 200));
        stage.setTitle(FXUtils.version());
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(DatePickerConfig.class.getName());

}