java - JavaFX 中的可编辑 TableView,仅输入数字

标签 java javafx tableview

我正在尝试在 JavaFX 中创建一个可编辑的 TableView,显示存储在自定义类 InventoryLocation 中的各种值。其中一些值是字符串,而另一些是各种数字数据类型(short、int、double),并且一些字符串具有与之关联的特定要求格式。我正在使用类似于以下代码块的东西来定义每个表列,使用 SortStringConverter() 或类似的方法来获取文本输入并将其转换为目标数据类型:

    TableColumn<InventoryLocation,Short> CabinetColumn = new TableColumn<>("Cabinet");
    CabinetColumn.setMinWidth(50);
    CabinetColumn.setCellValueFactory(new PropertyValueFactory<>("Cabinet"));
    CabinetColumn.setCellFactory(TextFieldTableCell.forTableColumn(new ShortStringConverter()));

但是,我想一开始就阻止用户输入任何无效数据。对于上面的例子,他们应该不能输入任何非数字字符。在我的应用程序的其他地方,在简单的 TextFields 中,我使用类似这样的东西来强制对用户输入进行 Regex 匹配:

    quantity.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            if (!newValue.matches("\\d*")) {
                quantity.setText(newValue.replaceAll("[^\\d]", ""));
            }
        }
    });

如何应用类似于可编辑 TableView 使用的文本条目的内容?目前,第一个代码块将允许用户写入他们喜欢的任何值,并在字符串无法转换为短整数时抛出数字格式异常。我希望代码能够防止他们首先输入无效值。

最佳答案

您需要创建一个自定义表格单元格 - 例如:

public class EditableBigDecimalTableCell<T> extends TableCell<T, BigDecimal> {
private TextField textField;
private int minDecimals, maxDecimals;
/**
 * This is the default - we will use this as 2 decimal places
 */
public EditableBigDecimalTableCell () {
    minDecimals = 2;
    maxDecimals = 2;
}

/**
 * Used when the cell needs to have a different behavior than 2 decimals
 */
public EditableBigDecimalTableCell (int min, int max) {
    minDecimals = min;
    maxDecimals = max;
}

@Override
public void startEdit() {
    if(editableProperty().get()){
        if (!isEmpty()) {
            super.startEdit();
            createTextField();
            setText(null);
            setGraphic(textField);
            textField.requestFocus();
        }
    }
}

@Override
public void cancelEdit() {
    super.cancelEdit();
    setText(getItem() != null ? getItem().toPlainString() : null);
    setGraphic(null);
}

@Override
public void updateItem(BigDecimal item, boolean empty) {
    super.updateItem(item, empty);
    if (empty) {
        setText(null);
        setGraphic(null);
    } else {
        if (isEditing()) {
            if (textField != null) {
                textField.setText(getString());
                textField.selectAll();
            }
            setText(null);
            setGraphic(textField);
        } else {
            setText(getString());
            setGraphic(null);
        }
    }
}

private void createTextField() {
    textField = new TextField();
    textField.setTextFormatter(new DecimalTextFormatter(minDecimals, maxDecimals));
    textField.setText(getString());

    textField.setOnAction(evt -> {
        if(textField.getText() != null && !textField.getText().isEmpty()){
            NumberStringConverter nsc = new NumberStringConverter();
            Number n = nsc.fromString(textField.getText());
            commitEdit(BigDecimal.valueOf(n.doubleValue()));
        }
    });
    textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);

    textField.setOnKeyPressed((ke) -> {
        if (ke.getCode().equals(KeyCode.ESCAPE)) {
            cancelEdit();
        }
    });

    textField.setAlignment(Pos.CENTER_RIGHT);
    this.setAlignment(Pos.CENTER_RIGHT);
}

private String getString() {
    NumberFormat nf = NumberFormat.getNumberInstance();
    nf.setMinimumFractionDigits(minDecimals);
    nf.setMaximumFractionDigits(maxDecimals);
    return getItem() == null ? "" : nf.format(getItem());
}

@Override
public void commitEdit(BigDecimal item) {
    if (isEditing()) {
        super.commitEdit(item);
    } else {
        final TableView<T> table = getTableView();
        if (table != null) {
            TablePosition<T, BigDecimal> position = new TablePosition<T, BigDecimal>(getTableView(),
                    getTableRow().getIndex(), getTableColumn());
            CellEditEvent<T, BigDecimal> editEvent = new CellEditEvent<T, BigDecimal>(table, position,
                    TableColumn.editCommitEvent(), item);
            Event.fireEvent(getTableColumn(), editEvent);
        }
        updateItem(item, false);
        if (table != null) {
            table.edit(-1, null);
        }

    }
}

}

使用格式化程序来阻止您不想要的值。

public class DecimalTextFormatter extends TextFormatter<Number> {
private static DecimalFormat format = new DecimalFormat( "#.0;-#.0" );
public DecimalTextFormatter(int minDecimals, int maxDecimals) {
    super(
        new StringConverter<Number>() {
            @Override
            public String toString(Number object) {
                if(object == null){
                    return "";
                }
                String format = "0.";
                for (int i = 0; i < maxDecimals; i++) {
                    if(i < minDecimals ) {
                        format = format + "0" ;
                    }else {
                        format = format + "#" ;
                    }
                }
                format = format + ";-" + format;
                DecimalFormat df = new DecimalFormat(format);
                String formatted =  df.format(object);
                return formatted;
            }

            @Override
            public Number fromString(String string){
                try {
                    return format.parse(string);
                } catch (ParseException e) {
                    return null;
                }
            }
        },
        0,
        new UnaryOperator<TextFormatter.Change>() {
            @Override
            public TextFormatter.Change apply(TextFormatter.Change change) {
                if ( change.getControlNewText().isEmpty() )
                {
                    return change;
                }

                ParsePosition parsePosition = new ParsePosition( 0 );
                Object object = format.parse( change.getControlNewText(), parsePosition );

                if(change.getControlNewText().equals("-")){
                    return change;
                }

                if(change.getCaretPosition() == 1){
                    if(change.getControlNewText().equals(".")){
                        return change;
                    }
                }

                if ( object == null || parsePosition.getIndex() < change.getControlNewText().length() )
                {
                    return null;
                }
                else
                {
                    int decPos = change.getControlNewText().indexOf(".");
                    if(decPos > 0){
                        int numberOfDecimals = change.getControlNewText().substring(decPos+1).length();
                        if(numberOfDecimals > maxDecimals){
                            return null;
                        }
                    }
                    return change;
                }
            }
        }
    );
}

然后在您的专栏中使用它:

numberColumn.setCellFactory(col -> new EditableBigDecimalTableCell<MyDTO>());

关于java - JavaFX 中的可编辑 TableView,仅输入数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45200797/

相关文章:

java - 如何使用SAP jco登录多个SAP系统

Java 使用递归进行乘法

java - 如何将 Spring bean 注入(inject)到 Seam 上下文中?

java - Stage 在 javafx 中显示为 null

JavaFX 8 : Unstable interactive TabPane when adding new Tab

python - 从 tableView 模型打印单击行的数据

java - 使用密码的 Windows 7 登录脚本

java - 在 JavaFX 中获取行号

iphone - UITableView如何改变颜色?

core-data - 调用多个CoreData键值进行tableview单元格显示