我正在寻找一种将自动完成功能添加到JavaFX的方法ComboBox。经过大量搜索之后,该在这里提问了。
这AutoFillBox是已知的,但不是我要搜索的内容。我想要的是一个可编辑的组合框,在键入列表时应进行过滤。但是我也想打开列表而不输入并查看整个项目。
任何想法?
我找到了一个对我有用的解决方案:
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);
基于此,我根据自己的需要对其进行了自定义。
随时使用它,如果有人可以改进它,请告诉我。
首先,你必须在项目中创建此类:
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));
当需要从组合框中获取选定的值时,还请确保使用此方法,否则你可能会遇到一些异常,例如“类强制转换异常”:
FxUtilTest.getComboBoxValue(myComboBox);
PS:在jre 8.51和8.65之间的版本中,此方法存在一些问题,导致了一些奇怪的行为,现在问题似乎不再发生了。如果你遇到问题,则可以查看对此答案所做的修改,并获取可以解决该问题的旧版本。此方法必须可以正常工作,如果你遇到任何问题,请告诉我。