JavaFX 触发 ChoiceBox 转换器(并按字符串值排序)

问题描述 投票:0回答:1

我有一个

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();
});
java javafx
1个回答
0
投票

如果您想在项目转换为字符串的方式发生变化时触发更新,那么您应该用新的转换器替换当前的转换器。最好的方法是使用绑定。例如,使用

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
    绑定的创建。

© www.soinside.com 2019 - 2024. All rights reserved.