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 116 117 118
| public final class AutoFillComboBox<T> extends Region {
private final ComboBox<T> comboBox = new ComboBox<>();
public AutoFillComboBox() {
super();
getStyleClass().add("auto-fill-combo-box");
getChildren().add(comboBox);
comboBox.setItems(filteredItems);
comboBox.editableProperty().bind(editableProperty());
// @todo Bind all other properties here.
comboBox.addEventFilter(KeyEvent.KEY_PRESSED, this::hideCombo);
comboBox.addEventFilter(KeyEvent.KEY_RELEASED, this::fillCombo);
//
setMinSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
}
@Override
protected void layoutChildren() {
super.layoutChildren();
final Insets insets = getInsets();
final double width = getWidth();
final double height = getHeight();
layoutInArea(comboBox, insets.getLeft(), insets.getTop(), width - (insets.getLeft() + insets.getRight()), height - (insets.getTop() + insets.getBottom()), 0, HPos.LEFT, VPos.TOP);
}
////////////////////////////////////////////////////////////////////////////
private void hideCombo(final KeyEvent keyEvent) {
comboBox.hide();
}
private void fillCombo(final KeyEvent keyEvent) {
if (keyEvent.isControlDown()) {
return;
}
final TextField comboEditor = comboBox.getEditor();
final String comboText = comboEditor.getText();
System.out.println(keyEvent.getCode());
int anchorPosition = comboEditor.getAnchor();
int caretPosition = comboEditor.getCaretPosition();
System.out.printf("current text: \"%s\"", comboText).println();
switch (keyEvent.getCode()) {
case HOME:
case END:
case TAB:
case SHIFT:
return;
case RIGHT:
caretPosition = Math.max(comboText.length(), caretPosition + 1);
break;
case LEFT:
caretPosition = Math.max(0, caretPosition - 1);
break;
case UP:
comboEditor.positionCaret(comboText.length());
break;
case DOWN:
if (!comboBox.isShowing()) {
comboBox.show();
}
return;
case BACK_SPACE:
caretPosition = Math.max(0, caretPosition - 1);
break;
case DELETE:
break;
default:
}
final String toSearch = (caretPosition <= 0 && anchorPosition <= 0) ? comboText : comboText.substring(0, caretPosition);
System.out.printf("search text: \"%s\"", toSearch).println();
filteredItems.setPredicate(value -> {
final String text = (value == null) ? "" : value.toString();
return toSearch.trim().isEmpty() ? true : text.startsWith(toSearch);
});
if (!filteredItems.isEmpty()) {
comboBox.show();
Platform.runLater(() -> {
final String newText = toSearch.isEmpty() ? "" : filteredItems.get(0).toString();
comboEditor.setText(newText);
comboEditor.selectRange(newText.length(), toSearch.length());
});
}
}
////////////////////////////////////////////////////////////////////////////
private final ListProperty<T> items = new SimpleListProperty(this, "items", FXCollections.observableList(new LinkedList<>())); // NOI18N.
private final FilteredList<T> filteredItems = new FilteredList<>(items);
public final ObservableList<T> getItems() {
return items.get();
}
public final void getItems(final ObservableList<T> value) {
items.set(value);
}
public final ListProperty<T> itemsProperty() {
return items;
}
private final BooleanProperty editable = new SimpleBooleanProperty(this, "editable"); // NOI18N.
public final boolean isEditable() {
return editable.get();
}
public final void setEditable(final boolean value) {
editable.set(value);
}
public final BooleanProperty editableProperty() {
return editable;
}
// @todo Implement all other properties from ComboBox here!
} |
Partager