ListView验证编辑并阻止提交

时间:2016-02-08 23:10:40

标签: javafx-8

我正在使用包含await的可编辑ListView。 用户可以查看和编辑列表中的正则表达式,我想在提交值之前验证正则表达式是否在语法上正确(并向用户提供红色边框等反馈)。

有办法吗?

Pattern

2 个答案:

答案 0 :(得分:4)

我会通过创建TableCell实现来实现此目的。 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() {
        super.cancelEdit();
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }

    @Override
    public void commitEdit(String newValue) {
        super.commitEdit(newValue);
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }

    @Override
    public void startEdit() {
        super.startEdit();
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        textField.selectAll();
        textField.requestFocus();
    }
}

这将谓词作为参数;对于有效文本,谓词返回true,对于无效文本,谓词返回false。它在单元格上设置一个CSS伪类,因此您可以使用CSS来设置文本字段(或者单元格本身,如果需要)的样式。

这是一个简单的示例,它以不同方式验证三个不同的列:

import java.util.function.Function;
import java.util.function.Predicate;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class ValidatingTableExample extends Application {

    private static <S> TableColumn<S, String> column(String title, Function<S, StringProperty> property, 
            Predicate<String> validator) {
        TableColumn<S, String> col = new TableColumn<>(title);
        col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        col.setCellFactory(tc -> new ValidatingEditingCell<>(validator));
        col.setPrefWidth(150);
        return col ;
    }

    @Override
    public void start(Stage primaryStage) {
        TableView<Address> table = new TableView<>();
        table.setEditable(true);
        table.getColumns().add(column("City", Address::cityProperty, s -> ! s.isEmpty()));
        table.getColumns().add(column("State", Address::stateProperty, s -> s.length()==2));
        table.getColumns().add(column("Zip", Address::zipProperty, s -> s.matches("\\d{5}")));

        Button newAddress = new Button("Add");
        newAddress.setOnAction(e -> {
            table.getItems().add(new Address("City", "State", "Zip"));
        });

        Button debug = new Button("Debug");
        debug.setOnAction(e -> 
                table.getItems().stream()
                    .map(address -> String.format("%s, %s %s", address.getCity(), address.getState(), address.getZip()))
                    .forEach(System.out::println));

        HBox buttons = new HBox(5, newAddress, debug);
        buttons.setAlignment(Pos.CENTER);
        buttons.setPadding(new Insets(5));

        BorderPane root = new BorderPane(table, null, null, buttons, null);
        Scene scene = new Scene(root, 600, 600);
        scene.getStylesheets().add(getClass().getResource("validating-cell.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static class Address {
        private final StringProperty city = new SimpleStringProperty();
        private final StringProperty state = new SimpleStringProperty();
        private final StringProperty zip = new SimpleStringProperty();

        public Address(String city, String state, String zip) {
            setCity(city);
            setState(state);
            setZip(zip);
        }

        public final StringProperty cityProperty() {
            return this.city;
        }


        public final String getCity() {
            return this.cityProperty().get();
        }


        public final void setCity(final String city) {
            this.cityProperty().set(city);
        }


        public final StringProperty stateProperty() {
            return this.state;
        }


        public final String getState() {
            return this.stateProperty().get();
        }


        public final void setState(final String state) {
            this.stateProperty().set(state);
        }


        public final StringProperty zipProperty() {
            return this.zip;
        }


        public final String getZip() {
            return this.zipProperty().get();
        }


        public final void setZip(final String zip) {
            this.zipProperty().set(zip);
        }



    }

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

和一些示例CSS:

.table-cell:invalid .text-field {
    -fx-focus-color: red ;
    -fx-control-inner-background: #ffc0c0 ;
    -fx-accent: red ;
}

答案 1 :(得分:0)

我终于通过覆盖commitEdit()的{​​{1}}方法找到了一种方法:

TextFieldListCell