Share the post "How To Create AutoComplete ComboBox Or TextField In Java FX 2"
Well, since there is no built-in class that does this functionality, the only solution was to create my own. Here is my version of an auto-complete class that can be used for a TextField or editable ComboBox.
If you want to use this for a TextField node, just change parts of the code to cater to it. It should not be hard.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
public class AutoCompleteComboBoxListener implements EventHandler<KeyEvent> { private ComboBox comboBox; private StringBuilder sb; private int lastLength; public AutoCompleteComboBoxListener(ComboBox comboBox) { this.comboBox = comboBox; sb = new StringBuilder(); this.comboBox.setEditable(true); this.comboBox.setOnKeyReleased(AutoCompleteComboBoxListener.this); // add a focus listener such that if not in focus, reset the filtered typed keys this.comboBox.getEditor().focusedProperty().addListener(new ChangeListener<Boolean>() { @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { if (newValue) { // in focus } else { lastLength = 0; sb.delete(0, sb.length()); selectClosestResultBasedOnTextFieldValue(false, false); } } }); this.comboBox.setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { selectClosestResultBasedOnTextFieldValue(true, true); } }); } @Override public void handle(KeyEvent event) { // this variable is used to bypass the auto complete process if the length is the same. // this occurs if user types fast, the length of textfield will record after the user // has typed after a certain delay. if (lastLength != (comboBox.getEditor().getLength() - comboBox.getEditor().getSelectedText().length())) lastLength = comboBox.getEditor().getLength() - comboBox.getEditor().getSelectedText().length(); if (event.isControlDown() || event.getCode() == KeyCode.BACK_SPACE || event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT || event.getCode() == KeyCode.DELETE || event.getCode() == KeyCode.HOME || event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB ) return; IndexRange ir = comboBox.getEditor().getSelection(); sb.delete(0, sb.length()); sb.append(comboBox.getEditor().getText()); // remove selected string index until end so only unselected text will be recorded try { sb.delete(ir.getStart(), sb.length()); } catch (Exception e) { } ObservableList items = comboBox.getItems(); for (int i=0; i<items.size(); i++) { if (items.get(i).toString().toLowerCase().startsWith(comboBox.getEditor().getText().toLowerCase()) ) { try { comboBox.getEditor().setText(sb.toString() + items.get(i).toString().substring(sb.toString().length())); } catch (Exception e) { comboBox.getEditor().setText(sb.toString()); } comboBox.getEditor().positionCaret(sb.toString().length()); comboBox.getEditor().selectEnd(); break; } } } /* * selectClosestResultBasedOnTextFieldValue() - selects the item and scrolls to it when * the popup is shown. * * parameters: * affect - true if combobox is clicked to show popup so text and caret position will be readjusted. * inFocus - true if combobox has focus. If not, programmatically press enter key to add new entry to list. * */ private void selectClosestResultBasedOnTextFieldValue(boolean affect, boolean inFocus) { ObservableList items = AutoCompleteComboBoxListener.this.comboBox.getItems(); boolean found = false; for (int i=0; i<items.size(); i++) { if (AutoCompleteComboBoxListener.this.comboBox.getEditor().getText().toLowerCase().equals(items.get(i).toString().toLowerCase())) { try { ListView lv = ((ComboBoxListViewSkin) AutoCompleteComboBoxListener.this.comboBox.getSkin()).getListView(); lv.getSelectionModel().clearAndSelect(i); lv.scrollTo(lv.getSelectionModel().getSelectedIndex()); found = true; break; } catch (Exception e) { } } } String s = comboBox.getEditor().getText(); if (!found && affect) { comboBox.getSelectionModel().clearSelection(); comboBox.getEditor().setText(s); comboBox.getEditor().end(); } if (!inFocus && comboBox.getEditor().getText() != null && comboBox.getEditor().getText().trim().length() > 0) { // press enter key programmatically to have this entry added KeyEvent ke = KeyEvent.impl_keyEvent(comboBox, KeyCode.ENTER.toString(), KeyCode.ENTER.getName(), KeyCode.ENTER.impl_getCode(), false, false, false, false, KeyEvent.KEY_RELEASED); comboBox.fireEvent(ke); } } } |
To use this class, just do
|
1 |
new AutoCompleteComboBoxListener(myComboBox); |
Easy, right?
This class also includes an added feature wherein after you type something in the editable ComboBox and when you press the ENTER key, an action will take place: say, you want to save it to the database or something.
Note: the focus listener is now added to the ComboBox’s TextField component because in the development environment, it works fine. However, when deployed as an Applet, it does not work. Only when I shifted the focus listener to the ComboBox’s editor did it work correctly.