在JavaFX 8 DatePicker中更改语言

时间:2014-12-09 15:53:57

标签: javafx datepicker javafx-8

将DatePicker添加到我的应用程序时,我得到以下内容:

DatePicker

我认为这是因为我在计算机上使用了希伯来语。 如何将DatePicker的语言更改为英语?

2 个答案:

答案 0 :(得分:6)

您可以为Java虚拟机调用实例定义默认语言环境:

Locale.setDefault(Locale.ENGLISH);

或者,如果找不到区域设置,则需要在预先设定的常量中查找officially supported locales列表中的国家/地区代码,并创建“自定义”区域设置,如下所示:

Locale.setDefault(Locale("cs")) //locale for Czech language

start方法上。如果您还想为文本编辑器实现自定义格式化程序,则还应该将语言环境添加到格式化程序中。

这只是一个例子:

private final DateTimeFormatter formatter = 
        DateTimeFormatter.ofPattern("EEEE, d.MM.uuuu", Locale.ENGLISH);

@Override
public void start(Stage primaryStage) {
    Locale.setDefault(Locale.ENGLISH);

    DatePicker datePicker=new DatePicker();
    datePicker.setValue(LocalDate.now());
    datePicker.setConverter(new StringConverter<LocalDate>() {

        @Override
        public String toString(LocalDate object) {
            return object.format(formatter);
        }

        @Override
        public LocalDate fromString(String string) {
            return LocalDate.parse(string, formatter);
        }
    });
    StackPane root = new StackPane(datePicker);
    Scene scene = new Scene(root, 400, 400);

    primaryStage.setScene(scene);
    primaryStage.show();
}

修改

按照设计,DatePicker在应用于弹出窗口上显示的控件的所有格式中都使用Locale.getDefault()。这可以在com.sun.javafx.scene.control.skin.DatePickerContent类中查看。

除非您为控件更改这些格式化程序提供自定义外观,否则为了将DatePicker内容更改为英语,避免进一步更改其他本地化控件,可能会出现以下解决方法:

private final Locale myLocale = Locale.getDefault(Locale.Category.FORMAT);

@Override
public void start(Stage primaryStage) {
    DatePicker datePicker=new DatePicker();
    datePicker.setValue(LocalDate.now());
    datePicker.setOnShowing(e-> Locale.setDefault(Locale.Category.FORMAT,Locale.ENGLISH));
    datePicker.setOnShown(e-> Locale.setDefault(Locale.Category.FORMAT,myLocale));
    ...
}

编辑2

返回setOnShown上的原始区域设置太早了,因为如果用户更改了月份,则会使用原始区域设置并且无法正确显示。要开始工作,应该在setOnHidingsetOnAction上关闭它。

private final Locale myLocale = Locale.getDefault(Locale.Category.FORMAT);

@Override
public void start(Stage primaryStage) {
    DatePicker datePicker=new DatePicker();
    datePicker.setValue(LocalDate.now());
    datePicker.setOnShowing(e-> Locale.setDefault(Locale.Category.FORMAT,Locale.ENGLISH));
    datePicker.setOnHiding(e-> Locale.setDefault(Locale.Category.FORMAT,myLocale));
    datePicker.setOnAction(e-> Locale.setDefault(Locale.Category.FORMAT,myLocale));
    ...
}

答案 1 :(得分:1)

从fx9开始,将皮肤移到公共api中-因此,您可能考虑创建一个自定义皮肤,该皮肤可以配置每个选择器的区域设置。不幸的是,进行内部格式化的类仍然隐藏在内部结构中,因此调整需要变得肮脏。

如果您敢于/允许访问内部构件,一种方法是

  • 放置应在选择器的属性图中使用的特定于选择器的语言环境
  • 扩展DatePickerContent(内部类-脏!)以覆盖其(公共!这里没有危险)getLocale(),首先检查选择器的属性是否包含自定义语言环境-如果是,则返回该自定义语言环境,否则委托给super li>
  • 扩展DatePickerSkin以注入(需要反射访问-很脏!)自定义内容
  • 扩展DatePicker以将自定义外观作为默认外观返回
  • 配置选择器的年代和转换器以使用特定的区域设置-需要在编辑器中正确设置文本格式

示例代码:

public class DatePickerLocale extends Application {

    /**
     * Custom DatePickerContent that uses a per-picker Locale if 
     * available.
     */
    public static class XDatePickerContent extends DatePickerContent {

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

        @Override
        protected Locale getLocale() {
            if (datePicker != null) {
                Object locale = datePicker.getProperties().get("CONTROL_LOCALE");
                if (locale instanceof Locale) {
                    return (Locale) locale;
                }
            }
            return super.getLocale();
        }

    }

    /**
     * Custom DatePickerSkin that injects a custom content.
     */
    public static class XDatePickerSkin extends DatePickerSkin {

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

        @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() {
        LocalDate now = LocalDate.now();
        DatePicker picker = new DatePicker(now) {

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

        };

        Locale customLocale = Locale.CHINA;
        // config locale for content
        picker.getProperties().put("CONTROL_LOCALE", customLocale);
        // config locale for chronology/converter
        picker.setChronology(Chronology.ofLocale(customLocale));
        picker.setConverter(new LocalDateStringConverter(FormatStyle.SHORT, 
                customLocale, picker.getChronology()));
        // just to see some formats with default locale
        List<String> patterns = List.of("e", "ee", "eee", "eeee", "eeeee");
        HBox box = new HBox(10);
        patterns.forEach(p -> {
            DateTimeFormatter ccc = DateTimeFormatter.ofPattern(p);
            String name = ccc.withLocale(Locale.getDefault(Locale.Category.FORMAT)).format(now);
            box.getChildren().add(new Label(name));
        });

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

    @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(DatePickerLocale.class.getName());

}