我有一个
ChoiceBox<Locale>
和一个 ChoiceBox<SavingOrder>
(我创建的枚举,它只有一个 geti18nKey()
方法),当语言环境发生变化时,我需要更新 SavingOrder
翻译。
有什么办法可以触发它的转换器吗?另外,我可以对显示的字符串进行排序吗?
setChoiceBoxItems(settingsLangCB, supportedLocales);
settingsLangCB.setConverter(new StringConverter<Locale>() {
@Override
public String toString(Locale locale) {
String str = locale.getDisplayLanguage(locale);
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
@Override
public Locale fromString(String string) {
return null;
}
});
settingsLangCB.getSelectionModel().select(ioManager.getLoginAccount().getLocale());
settingsLangCB.setOnAction(event -> {
Locale locale = settingsLangCB.getSelectionModel().getSelectedItem();
langResources.setResources(ResourceBundle.getBundle("/bundles/Lang", locale));
ioManager.getLoginAccount().setLocale(locale);
// TODO on lang change call settingsOrderCB's converter so that is displayed in the right lang
// and sort it by the associated String value
setMainTitle(langResources.getValue("settings"));
});
setChoiceBoxItems(settingsOrderCB, SavingOrder.class.getEnumConstants());
settingsOrderCB.setConverter(new StringConverter<SavingOrder>() {
@Override
public String toString(SavingOrder savingOrder) {
return langResources.getValue(savingOrder.i18nKey());
}
@Override
public SavingOrder fromString(String string) {
return null;
}
});
settingsOrderCB.getSelectionModel().select(ioManager.getLoginAccount().getSavingOrder());
settingsOrderCB.setOnAction(event -> {
SavingOrder savingOrder = settingsOrderCB.getSelectionModel().getSelectedItem();
ioManager.getLoginAccount().setSavingOrder(savingOrder);
ioManager.sortAccountList();
});
如果您想在项目转换为字符串的方式发生变化时触发更新,那么您应该用新的转换器替换当前的转换器。最好的方法是使用绑定。例如,使用
ChoiceBox<Locale>
,您可以执行以下操作:
var langBox = new ChoiceBox<Locale>();
langBox.converterProperty().bind(langBox.valueProperty().map(locale -> {
return new StringConverter<>() {
@Override
public Locale fromString(String string) {
throw new UnsupportedOperationException();
}
@Override
public String toString(Locale object) {
var string = object.getDisplayLanguage(locale);
return string.substring(0, 1).toUpperCase(locale) + string.substring(1);
}
};
}));
注意:
ObservableValue::map
方法是在JavaFX 19中添加的。
至于按字符串表示形式对
ChoiceBox
的项目进行排序,您可以使用 SortedList
和自定义 Comparator
。您可以使用现有的 StringConverter
来获取每个项目的字符串表示形式。为了使排序保持最新,您可以将排序列表的比较器绑定到当前区域设置和转换器,类似于上面处理转换器的方式。例如(从上一个代码块继续):
var langs = langBox.getItems();
var sortedLangs = langs.sorted(null);
langBox.setItems(sortedLangs); // must set the items to the SortedList
// javafx.beans.binding.Bindings
sortedLangs.comparatorProperty().bind(Bindings.createObjectBinding(() -> {
var locale = langBox.getValue();
var converter = langBox.getConverter();
var collator = java.text.Collator.getInstance(locale);
// This comparator will convert the items to strings using the same
// converter used to display the items, then compare those strings using
// the given Collator. If you don't want to use the Collator then you
// don't have to; you can simply remove that argument since strings
// implement Comparable.
return Comparator.comparing(converter::toString, collator);
}, langBox.valueProperty(), langBox.converterProperty()));
注意: 您不能直接修改
SortedList
。如果您需要添加、删除或替换项目,那么您需要修改支持 ObservableList
的 SortedList
(在上面,即为 langs
)。
您也可以为您的
ChoiceBox<SavingOrder>
做类似的事情。
顺便说一句,一些可能有助于使代码更具可读性的事情包括:
将您的
StringConverter
实现移至它们自己的源文件中。
创建一个方法(甚至可能是一个类)来概括
Comparator
绑定的创建。