JavaFX: Capture "Enter" key pressed

Will picture Will · Oct 22, 2014 · Viewed 8.5k times · Source

I need to keep an indeterminably sized list of strings. I figured the best way to do this would be through a combo box which would take user input, and in turn add that user input upon an "Enter" keystroke detected to the ComboBox list of items, and also allow the user to remove those items by a "Delete" keystroke.

I had hoped this would be a very simple task handled like so:

    this.cbx.setOnKeyTyped((KeyEvent E) -> {
        switch(E.getCode()){
            case  ENTER:
                this.cbx.getItems().add(this.cbx.valueProperty().get());
                this.cbx.valueProperty().set("");
                E.consume();
                break;
            case DELETE:
                if (this.cbx.getItems().contains(
                    this.cbx.valueProperty().get()
                )) this.cbx.getItems().remove(this.cbx.valueProperty().get());
                this.cbx.valueProperty().set("");
                E.consume();
                break;
        }
    });

Unfortunately, Enter does not trigger the event. So clearly I am mistaken. I also tried with onKeyPressed, and that did not work either. What need I do to capture when "Enter" and "Delete" are pressed (It picks up "Shift" just fine which is maddening).

EDIT 1:

Have also tried with

If(E.getCode().Equals(KeyCode.ENTER)){
    ...
} else if (E.getCode().equals(KeyCode.DELETE)){
    ...
}

No Love.

Edit 2:

Based on James_D's answer below which put me on the right course, in order to accomplish what I was seeking to do, I employed the following method:

    ComboBox<String> cb = new ComboBox<>();
    cb.setEditable(true);
    cb.getEditor().addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent E) -> {
        switch(E.getCode()){
            case ENTER:{
                if (cb.getItems().contains(cb.getEditor().getText()))
                    E.consume();
                else{
                    cb.getItems().add(cb.getEditor().getText());
                    cb.getEditor().clear();
                    E.consume();
                }
                break;
            }
            case DELETE:{
                if (E.isControlDown() && cb.getItems().contains(cb.getEditor().getText()))
                    cb.getItems().remove(cb.getEditor().getText());
                else if (E.isAltDown()) cb.getItems().clear();

                if (E.isControlDown() || E.isAltDown()){
                    cb.getEditor().clear();
                    E.consume();
                }
                break;
            }
        }
    });

Answer

James_D picture James_D · Oct 22, 2014

Are you looking to have an editable combo box, that adds items to its popup list when the user types in items that are not there?

If so, try:

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class UpdatingComboBox extends Application {

    @Override
    public void start(Stage primaryStage) {
        ComboBox<String> combo = new ComboBox<>();
        combo.setEditable(true);
        combo.valueProperty().addListener((obs, oldValue, newValue) -> {
            if (newValue != null && ! combo.getItems().contains(newValue)) {
                combo.getItems().add(newValue);
            }
        });
        HBox root = new HBox(combo);
        root.setAlignment(Pos.TOP_CENTER);
        primaryStage.setScene(new Scene(root, 350, 150));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

For deleting, the first thing I would ask is if you really want the functionality as you've described it. Users would typically expect pressing delete in an editable combo box to delete the next character, not remove an item entirely from the list. If you do want to do this, you have to get your hands a little more dirty and use a key listener. For some reason, adding the key listener to the combo box directly seems to have somewhat unpredictable results; it works however if you add it to the text field underlying the editable combo box:

    combo.getEditor().addEventFilter(KeyEvent.KEY_PRESSED, event -> {
        if (event.getCode() == KeyCode.DELETE) {
            combo.getItems().remove(combo.getValue());
            event.consume();
        }
    });