更改JavaFX8日期选择器中的语言

更改JavaFX8日期选择器中的语言,javafx,datepicker,javafx-8,Javafx,Datepicker,Javafx 8,将日期选择器添加到我的应用程序时,我得到以下信息: 我想这是因为我在电脑上用希伯来语。 如何将日期选择器的语言更改为英语?您可以为Java虚拟机调用实例定义默认语言环境: Locale.setDefault(Locale.ENGLISH); 或者,如果您找不到区域设置,您需要在预先制作的常量中,在列表中查找国家代码并创建“自定义”区域设置,如下所示: Locale.setDefault(Locale("cs")) //locale for Czech language 在start方法上。

将日期选择器添加到我的应用程序时,我得到以下信息:

我想这是因为我在电脑上用希伯来语。
如何将日期选择器的语言更改为英语?

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

Locale.setDefault(Locale.ENGLISH);
或者,如果您找不到区域设置,您需要在预先制作的常量中,在列表中查找国家代码并创建“自定义”区域设置,如下所示:

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();
}
编辑2

setOnShown
上返回原始区域设置为时过早,因为如果用户更改月份,将使用原始区域设置,并且不会正确显示。要工作,应同时关闭
setOnHiding
setOnAction

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));
    ...
}

从FX9开始,将皮肤移到公共API中,因此您可以考虑创建一个自定义皮肤,允许配置每个选择器的区域设置。不幸的是,进行内部格式化的类仍然隐藏在内部,因此调整需要进行修改

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

  • 在选择器的属性映射中放置应使用的选择器特定区域设置
  • 扩展DatePickerContent(内部类-dirty!)以覆盖其(public!此处无危险)
    getLocale()
    以首先检查选择器的属性是否包含自定义区域设置-如果是,则返回该区域设置,否则委托给super
  • 扩展DatePickerSkin以注入(需要反射访问-脏!)自定义内容
  • 扩展DatePicker以返回自定义外观作为其默认外观
  • 配置选择器的cronology和converter以使用特定的语言环境-这是适当设置编辑器中文本格式所必需的
示例代码:

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());

}
公共类DatePickerLocale扩展应用程序{
/**
*自定义DatePickerContent,在以下情况下使用每个选取器区域设置
*可用。
*/
公共静态类XDatePickerContent扩展了DatePickerContent{
公共XDatePickerContent(日期选择器日期选择器){
超级(日期选择器);
}
@凌驾
受保护的区域设置getLocale(){
if(日期选择器!=null){
对象区域设置=datePicker.getProperties().get(“CONTROL_locale”);
if(locale instanceof locale){
返回(Locale)Locale;
}
}
返回super.getLocale();
}
}
/**
*注入自定义内容的自定义DatePickerSkin。
*/
公共静态类XDatePickerSkin扩展了DatePickerSkin{
公共XDatePickerSkin(日期选择器控件){
超级(控制);
}
@凌驾
公共节点getPopupContent(){
DatePickerContent内容=(XDatePickerContent)getDatePickerContent();
if(!(XDatePickerContent的内容实例)){
content=newxDatePickerContent((日期选择器)getSkinnable());
replaceDatePickerContent(内容);
}
返回内容;
}
//-------------变脏:反射式访问超级
受保护的DatePickerContent getDatePickerContent(){
return(DatePickerContent)FXUtils.invokeGetFieldValue(DatePickerSkin.class,此为“DatePickerContent”);
}
受保护的void replaceDatePickerContent(DatePickerContent内容){
invokeSetFieldValue(DatePickerSkin.class,这个“datePickerContent”,content);
}
}
私有父createContent(){
LocalDate now=LocalDate.now();
DatePicker-picker=新的日期选择器(现在){
@凌驾
受保护的皮肤createDefaultSkin(){
返回新的XDatePickerSkin(此);
}
};
Locale customLocale=Locale.CHINA;
//为内容配置区域设置
picker.getProperties();
//为年表/转换器配置区域设置
设置时间顺序(按时间顺序排列的比例(自定义语言环境));
picker.setConverter(新的LocalDateStringConverter(FormatStyle.SHORT,
customLocale,picker.getchronoloy());
//只是想看看一些默认语言环境的格式
列表模式=列表中的(“e”、“ee”、“eee”、“eeee”、“eeee”);
HBox盒=新的HBox(10);
模式。forEach(p->{
DateTimeFormatter ccc=模式的DateTimeFormatter.of(p);
String name=ccc.withLocale(Locale.getDefault(Locale.Category.FORMAT)).FORMAT(现在);
box.getChildren().add(新标签(名称));
});
边框窗格内容=新边框窗格(选择器);
content.setBottom(框);
返回内容;
}
@凌驾
public void start(Stage)引发异常{
stage.setScene(新场景(createContent(),400200));
stage.setTitle(FXUtils.version());
stage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
@抑制警告(“未使用”)
专用静态最终记录器日志=记录器
.getLogger(DatePickerLocale.class.getName());
}

谢谢您的回复。但是,更改默认区域设置也会更改其他内容,例如日期格式,这对于美国和欧洲用户来说应该是不同的(MM/DD,DD/MM)。是否可以在不更改我的应用程序其余部分的默认区域设置的情况下执行此操作?谢谢您的回复。这是可行的,只是在“setOnShown”上返回原始本地太快了,因为如果用户更改月份,将使用原始区域设置,并且不会正确显示。若要工作,应在“setOnHiding”和“setOnAction”上关闭它。我会编辑你的回复
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());

}