当前位置: 首页 > 知识库问答 >
问题:

JavaFX中的自动完成组合框

秦学林
2023-03-14

我正在寻找一种将自动完成添加到JavaFX组合框的方法。

这个AutoFillBox是已知的,但不是我正在搜索的。我想要的是一个可编辑的组合框,在输入时,列表应该被过滤掉。但我也想打开列表,而不必输入和查看所有项目。

知道吗?

共有3个答案

谭健柏
2023-03-14

使用ControlsFX库,您可以使用两行代码来完成:

comboBox.setEditable(true);
TextFields.bindAutoCompletion(comboBox.getEditor(), comboBox.getItems());
虞展
2023-03-14

我找到了一个适合我的解决方案:

public class AutoCompleteComboBoxListener<T> implements EventHandler<KeyEvent> {

    private ComboBox comboBox;
    private StringBuilder sb;
    private ObservableList<T> data;
    private boolean moveCaretToPos = false;
    private int caretPos;

    public AutoCompleteComboBoxListener(final ComboBox comboBox) {
        this.comboBox = comboBox;
        sb = new StringBuilder();
        data = comboBox.getItems();

        this.comboBox.setEditable(true);
        this.comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {

            @Override
            public void handle(KeyEvent t) {
                comboBox.hide();
            }
        });
        this.comboBox.setOnKeyReleased(AutoCompleteComboBoxListener.this);
    }

    @Override
    public void handle(KeyEvent event) {

        if(event.getCode() == KeyCode.UP) {
            caretPos = -1;
            moveCaret(comboBox.getEditor().getText().length());
            return;
        } else if(event.getCode() == KeyCode.DOWN) {
            if(!comboBox.isShowing()) {
                comboBox.show();
            }
            caretPos = -1;
            moveCaret(comboBox.getEditor().getText().length());
            return;
        } else if(event.getCode() == KeyCode.BACK_SPACE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        } else if(event.getCode() == KeyCode.DELETE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        }

        if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT
                || event.isControlDown() || event.getCode() == KeyCode.HOME
                || event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
            return;
        }

        ObservableList list = FXCollections.observableArrayList();
        for (int i=0; i<data.size(); i++) {
            if(data.get(i).toString().toLowerCase().startsWith(
                AutoCompleteComboBoxListener.this.comboBox
                .getEditor().getText().toLowerCase())) {
                list.add(data.get(i));
            }
        }
        String t = comboBox.getEditor().getText();

        comboBox.setItems(list);
        comboBox.getEditor().setText(t);
        if(!moveCaretToPos) {
            caretPos = -1;
        }
        moveCaret(t.length());
        if(!list.isEmpty()) {
            comboBox.show();
        }
    }

    private void moveCaret(int textLength) {
        if(caretPos == -1) {
            comboBox.getEditor().positionCaret(textLength);
        } else {
            comboBox.getEditor().positionCaret(caretPos);
        }
        moveCaretToPos = false;
    }

}

你可以用

new AutoCompleteComboBoxListener<>(comboBox);

基于此,我根据自己的需要进行了定制。

请随意使用它,如果有人能改进它,告诉我。

万俟光临
2023-03-14

首先,您必须在项目中创建此类:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class FxUtilTest {

    public interface AutoCompleteComparator<T> {
        boolean matches(String typedText, T objectToCompare);
    }

    public static<T> void autoCompleteComboBoxPlus(ComboBox<T> comboBox, AutoCompleteComparator<T> comparatorMethod) {
        ObservableList<T> data = comboBox.getItems();

        comboBox.setEditable(true);
        comboBox.getEditor().focusedProperty().addListener(observable -> {
            if (comboBox.getSelectionModel().getSelectedIndex() < 0) {
                comboBox.getEditor().setText(null);
            }
        });
        comboBox.addEventHandler(KeyEvent.KEY_PRESSED, t -> comboBox.hide());
        comboBox.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {

            private boolean moveCaretToPos = false;
            private int caretPos;

            @Override
            public void handle(KeyEvent event) {
                if (event.getCode() == KeyCode.UP) {
                    caretPos = -1;
                    if (comboBox.getEditor().getText() != null) {
                        moveCaret(comboBox.getEditor().getText().length());
                    }
                    return;
                } else if (event.getCode() == KeyCode.DOWN) {
                    if (!comboBox.isShowing()) {
                        comboBox.show();
                    }
                    caretPos = -1;
                    if (comboBox.getEditor().getText() != null) {
                        moveCaret(comboBox.getEditor().getText().length());
                    }
                    return;
                } else if (event.getCode() == KeyCode.BACK_SPACE) {
                    if (comboBox.getEditor().getText() != null) {
                        moveCaretToPos = true;
                        caretPos = comboBox.getEditor().getCaretPosition();
                    }
                } else if (event.getCode() == KeyCode.DELETE) {
                    if (comboBox.getEditor().getText() != null) {
                        moveCaretToPos = true;
                        caretPos = comboBox.getEditor().getCaretPosition();
                    }
                } else if (event.getCode() == KeyCode.ENTER) {
                    return;
                }

                if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT || event.getCode().equals(KeyCode.SHIFT) || event.getCode().equals(KeyCode.CONTROL)
                        || event.isControlDown() || event.getCode() == KeyCode.HOME
                        || event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
                    return;
                }

                ObservableList<T> list = FXCollections.observableArrayList();
                for (T aData : data) {
                    if (aData != null && comboBox.getEditor().getText() != null && comparatorMethod.matches(comboBox.getEditor().getText(), aData)) {
                        list.add(aData);
                    }
                }
                String t = "";
                if (comboBox.getEditor().getText() != null) {
                    t = comboBox.getEditor().getText();
                }

                comboBox.setItems(list);
                comboBox.getEditor().setText(t);
                if (!moveCaretToPos) {
                    caretPos = -1;
                }
                moveCaret(t.length());
                if (!list.isEmpty()) {
                    comboBox.show();
                }
            }

            private void moveCaret(int textLength) {
                if (caretPos == -1) {
                    comboBox.getEditor().positionCaret(textLength);
                } else {
                    comboBox.getEditor().positionCaret(caretPos);
                }
                moveCaretToPos = false;
            }
        });
    }

    public static<T> T getComboBoxValue(ComboBox<T> comboBox){
        if (comboBox.getSelectionModel().getSelectedIndex() < 0) {
            return null;
        } else {
            return comboBox.getItems().get(comboBox.getSelectionModel().getSelectedIndex());
        }
    }

}

要使您的组合框自动完成,请如下使用:

FxUtilTest.autoCompleteComboBoxPlus(myComboBox, (typedText, itemToCompare) -> itemToCompare.getName().toLowerCase().contains(typedText.toLowerCase()) || itemToCompare.getAge().toString().equals(typedText));

然后,像下面的例子一样添加一个StringConverter(因为组合框值将返回一个字符串,并且必须将其转换为您的对象):

myComboBox.setConverter(new StringConverter<>() {

    @Override
    public String toString(YourObject object) {
        return object != null ? object.getName() : "";
    }

    @Override
    public YourObject fromString(String string) {
        return myComboBox.getItems().stream().filter(object ->
                object.getName().equals(string)).findFirst().orElse(null);
    }

});

当您需要从组合框中获取所选值时,请务必使用此方法,否则可能会遇到一些异常,如“类强制转换异常”:

FxUtilTest.getComboBoxValue(myComboBox);

附言:在JRE 8.51和8.65之间的版本中,这个方法有一些问题,导致了一些奇怪的行为,现在这些问题似乎不再发生了。如果你遇到一些问题,你可以看到对这个答案的编辑,并获得当时解决问题的旧版本。这个方法一定能正常工作,如果你遇到任何问题,请告诉我。

 类似资料:
  • 我正在寻找一种将自动完成添加到JavaFX的方法。 这个是已知的,但不是我正在搜索的。我想要的是一个可编辑的组合框,在输入时,列表应该被过滤掉。但我也想打开列表,而不必输入和查看所有项目。 知道吗?

  • 我实现了一个ComboBox,它是可编辑的,并自动完成自己,类似于这个答案中的一个:https://stackoverflow.com/a/27384068/9611276 现在我想添加一个侦听器,当这个组合框中的值发生变化时,它会执行一些操作。大概是这样的: 问题是,我无法访问组合框。getValueProperty()而不获取java。lang.ClassCastException。在上面的回

  • 问题内容: 有谁知道用Knockout JS模板创建自动完成组合框的最佳方法吗? 我有以下模板: 有时候,这个清单很长,我想让Knockout在jQuery自动完成功能或一些直接的JavaScript代码方面表现出色,但收效甚微。 另外,jQuery.Autocomplete需要输入字段。有任何想法吗? 问题答案: 这是我编写的jQuery UI自动完成绑定。它的目的是镜像,,,与几个新增的选择要

  • 问题内容: 我需要高效的产品项目搜索GUI到销售点应用程序,当前我正在文本字段中使用弹出窗口,并且该弹出窗口包含到表格中,但是效率不高。 在我的弹出窗口中仅显示产品代码,我需要显示其他产品详细信息,例如CODE,类别,名称,价格等。以确定正确的产品。![在此处输入图片描述] [1] 以下图片是我的要求。 /////////////////////////////请查看代码并帮助我进行开发。 以下是

  • 问题内容: 无法使jQuery自动完成小部件与Flask框架一起使用。(http://jqueryui.com/autocomplete/#remote这里是一个示例) 在manage.py中,我得到了以下内容: 我的index.html文件: 似乎firefox中的开发工具不会返回任何错误。终端返回以下内容: 小部件不起作用。由于我对jQuery知之甚少,所以我不知道是什么原因导致了问题。有人可

  • 我正在从Eclipse迁移到Intellij Idea。有一件事我还不明白,那就是自动完成JavaDoc标记。在Eclipse中键入时,有两个建议: 我如何在Intellij中实现第一个提议(这可能吗?)?如果可能的话,我如何更改为作者姓名占位符插入内容的模板?