具有自定义对象的可编辑组合框重写下拉列表中的项目

Editable ComboBox with custom objects rewrites items on dropdown list

我有一个可过滤的 ComboBox 填充自定义 Subjekt 对象。

使用 SubjektDAO.searchSubjectsByName() 方法从数据库填充过滤列表。

ComboBox 的编辑器添加了监听器,并使用 cbNazivKupca.show() 方法在我开始输入时自动打开下拉列表(填充并显示)。

过滤工作正常(当我输入列表时被过滤),但是当我 select 列表中的项目(比方说 "abraham")时,更改其在 ComboBox 文本字段中的值(让我们说 "abrah") 并单击其他地方(因此 ComboBox 失去焦点) "abrah" 值出现在下拉列表中,我失去了原始值。

我需要禁止在列表中输入新值(我可以通过将组合框设置为不可编辑来做到这一点)但是我有大量内容需要滚动浏览。

此外,如果我单击按钮以显示列表中的项目并单击行中的第一个,它会填充在文本框中,但如果我单击第二个或下一个我需要单击他两次(这只会发生一次).

我不知道如何解决这个问题,我是 JavaFX 的新手,正在学习。

请帮忙。

try {

    final FilteredList<Subjekt> filteredItems = new FilteredList<>(SubjektDAO.searchSubjectsByName(), p -> true);

    cbNazivKupca.getEditor().textProperty().addListener((obs, oldValue, newValue) -> {


        cbNazivKupca.show();

        final TextField editor = cbNazivKupca.getEditor();
        final Subjekt selected = cbNazivKupca.getSelectionModel().getSelectedItem();


    /*
    This needs run on the GUI thread to avoid the error described
    here: https://bugs.openjdk.java.net/browse/JDK-8081700.
    */

        Platform.runLater(() -> {

        /*
        If the no item in the list is selected or the selected item
        isn't equal to the current input, we refilter the list.
        */
            if (selected == null || !selected.toString().equals(editor.getText())) {
                filteredItems.setPredicate(item -> {
                    cbNazivKupca.setVisibleRowCount(10);
                    // We return true for any items that contains the
                    // same letters as the input. We use toUpperCase to
                    // avoid case sensitivity.
                    if (item.getSubjekt_naziv().toUpperCase().contains(newValue.toUpperCase())) {
                        return true;
                    } else {
                        return false;
                    }
                });
            }
        });
    });

    cbNazivKupca.setItems(filteredItems);
} catch (SQLException | ClassNotFoundException e) {
    e.printStackTrace();
}


//  rendering of the list of values in ComboBox drop down.
cbNazivKupca.setCellFactory((comboBox) -> {
    return new ListCell<Subjekt>() {
        @Override
        protected void updateItem(Subjekt subjekt, boolean empty) {
            super.updateItem(subjekt, empty);

            if (subjekt == null || empty) {
                setText(null);
            } else {
                setText(subjekt.getSubjekt_naziv());
            }
        }
    };
});

cbNazivKupca.setConverter(new StringConverter<Subjekt>() {
    @Override
    public String toString(Subjekt subjekt) {
        if (subjekt == null) {
            return null;
        } else {
            return subjekt.getSubjekt_naziv();
        }
    }

    @Override
    public Subjekt fromString(String productString)
    {
        if(cbNazivKupca.getValue() != null)
        {
            ((Subjekt)cbNazivKupca.getValue()).setSubjekt_naziv(productString);

            return (Subjekt)cbNazivKupca.getValue();
        }
        return null;

    }

});

已编辑:我已将问题的根源缩小到 cbNazivKupca.setConverter fromString 方法,但我卡住了,我需要检查是否 cbNazivKupca.getValue()出现在下拉列表中。

已编辑:我也遇到了类似的解决方案,但让我感到困惑的是: 当我单击下拉按钮并列出项目时,如果我单击列表中的第一个,它会被复制到可编辑部分,但如果我单击任何其他按钮,编辑器将获得光标并且为空,如果我再次单击它,一切都很好,这只会发生一次。

您的转换器的 fromString 方法无效。 this method的目的是return一个对象,其类型为StringConverter的泛型参数类型,没有别的:

Converts the string provided into an object defined by the specific converter. Format of the string and type of the resulting object is defined by the specific converter.

所以在这个方法中你不应该得到选择的项目,更糟糕的是你不应该修改选择的项目,实际上这就是修改下拉列表中的项目的原因。

当您在 ComboBox 的编辑器中输入时使用 fromString 方法,然后按回车键找出应选择的项目(该项目是方法 returns ) 基于您在编辑器中输入的字符串(方法的输入参数)。

你应该做的是从 ComboBox 的项目中获取对应的 Subject 实例,例如:

@Override
public Subjekt  fromString(String productString) {
    return cbNazivKupca.getItems().stream().filter(item -> productString.equals(item.getSubjekt_naziv())).findFirst().orElse(null);
}

这将 return ComboBox 中项目的第一个元素,其中 subjekt_naziv 成员与指定的 String 相同,如果无法匹配则为 null .