Joffrey February 2016

ListView validate edit and prevent commit

I'm using an editable ListView containing Patterns. The user can see and edit the regexs in the list, and I'd like to validate whether the regex is syntactically correct before committing the value (and give feedback like a red border to the user).

Is there a way to do so?

patternList.setCellFactory(TextFieldListCell.forListView(new StringConverter<Pattern>() {
    @Override
    public String toString(Pattern pattern) {
        return pattern.toString();
    }

    @Override
    public Pattern fromString(String string) {
        try {
            return Pattern.compile(string);
        } catch (PatternSyntaxException e) {
            return null;
        }
    }
}));
patternList.setOnEditCommit(e -> {
    if (e.getNewValue() == null) {
        // TODO pattern syntax error, prevent commit and stay in edit mode
    } else {
        patternList.getItems().set(e.getIndex(), e.getNewValue());
    }
});

Answers


Joffrey February 2016

I finally found a way, by overriding the commitEdit() method of TextFieldListCell:

patternList.setCellFactory(l -> new TextFieldListCell<Pattern>(new StringConverter<Pattern>() {
    @Override
    public String toString(Pattern pattern) {
        return pattern.toString();
    }

    @Override
    public Pattern fromString(String string) {
        try {
            return Pattern.compile(string);
        } catch (PatternSyntaxException e) {
            return null;
        }
    }
}) {
    @Override
    public void commitEdit(Pattern pattern) {
        if (!isEditing()) return;
        PseudoClass errorClass = PseudoClass.getPseudoClass("error");
        pseudoClassStateChanged(errorClass, pattern == null);
        if (pattern != null) {
            super.commitEdit(pattern);
        }
    }
});
patternList.setOnEditCommit(e -> patternList.getItems().set(e.getIndex(), e.getNewValue()));


James_D February 2016

I would do this by creating a TableCell implementation. E.g.:

import java.util.function.Predicate;

import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.css.PseudoClass;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class ValidatingEditingCell<S> extends TableCell<S, String> {

    private final TextField textField ;

    private static final PseudoClass INVALID = PseudoClass.getPseudoClass("invalid");

    private BooleanProperty valid = new SimpleBooleanProperty();

    public ValidatingEditingCell(Predicate<String> validator) {
        this.textField = new TextField();
        valid.bind(Bindings.createBooleanBinding(() -> textField.getText() != null && validator.test(textField.getText()), 
                textField.textProperty()));
        valid.addListener((obs, wasValid, isValid) -> {
            pseudoClassStateChanged(INVALID, ! isValid);
        });
        pseudoClassStateChanged(INVALID, ! valid.get());

        textField.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
            if (e.getCode() == KeyCode.ENTER && valid.get()) {
                commitEdit(textField.getText());
            }
            if (e.getCode() == KeyCode.ESCAPE) {
                cancelEdit();
            }
        });

        setGraphic(textField);
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }

    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        setText(empty ? null : item);
        textField.setText(empty ? null : item);
        setContentDisplay(isEditing() ? ContentDisplay.GRAPHIC_ONLY : ContentDisplay.TEXT_ONLY);
    }

    @Override
    public void cancelEdit() {
        s 

Post Status

Asked in February 2016
Viewed 3,038 times
Voted 11
Answered 2 times

Search




Leave an answer