javajavafxtablecell

How do you prevent a TextFieldTableCell from going into Edit mode when pressing the ENTER key?


By default, pressing ENTER on a TextFieldTableCell puts the cell into editing mode and draws a textField in the cell. How do I prevent this? I would only like the cell to enter Editing mode if a digit key is pressed. If ENTER is pressed, then it should simply select the cell below.

What I have tried:

tableView.setOnKeyReleased(new EventHandler<KeyEvent>() {
    @Override
    public void handle(KeyEvent event) {
        TablePosition tp;
        if(event.getCode().isDigitKey()) {
            lastKey = event.getText();
            tp = tableView.getFocusModel().getFocusedCell();
            tableView.edit(tp.getRow() , tp.getTableColumn());
        }
        if(tableView.getEditingCell() == null && event.getCode() == KeyCode.ENTER) {
            event.consume();
            tableView.getSelectionModel().selectBelowCell();
        }
    }
});

The cell still enters Editing mode.


Solution

  • An alternative to manually install filters/handlers on the table is to tweak the table's InputMap. Beware: that's private api, requires access to internal packages (inputmap and behavior) and reflective grabbing of the behavior from the skin. Hopefully, those packages will make it into public scope soon.

    The basic approach is

    In code:

    TableViewSkin<?> skin = (TableViewSkin<?>) table.getSkin();
    // use your favorite utility method to reflectively access the private field
    TableViewBehavior<?> listBehavior = (TableViewBehavior<?>) FXUtils.invokeGetFieldValue(
            TableViewSkin.class, skin, "behavior");
    InputMap<?> map = listBehavior.getInputMap();
    // remove old mapping for enter
    Optional<Mapping<?>> mapping = map.lookupMapping(new KeyBinding(ENTER));
    map.getMappings().remove(mapping.get());
    // add new mapping for enter
    map.getMappings().add(new KeyMapping(KeyCode.ENTER, e -> table.getSelectionModel().selectBelowCell()));
    // add mappings for digits
    EventHandler<KeyEvent> handler = e -> {
        TablePosition<T, ?> pos = table.getFocusModel().getFocusedCell() ;
        if (pos != null ) {
            table.edit(pos.getRow(), pos.getTableColumn());
        }
    };
    List<KeyMapping> digitMappings = Arrays.stream(KeyCode.values())
            .filter(c -> c.isDigitKey())
            .map(c -> new KeyMapping(c, handler))
            .collect(Collectors.toList());
                    
    map.getMappings().addAll(digitMappings);
    

    Obviously, this requires that the table's skin is available and that it is of type TableViewSkin. To use, it can be invoked in a listener to the table's skin property:

    table.skinProperty().addListener(c -> {
        tweakInputMap(table);
    });
    

    Should work in fx versions >= fx9 (my context is fx17/18 dev) and requires add-exports of inputmap/behavior packages at compile time and add-opens of these packages at runtime.