JavaFX中的可编辑TableView,仅数值输入

JavaFX中的可编辑TableView,仅数值输入,java,javafx,tableview,Java,Javafx,Tableview,我试图在JavaFX中创建一个可编辑的TableView,显示存储在自定义类InventoryLocation中的各种值。其中一些值是字符串,而另一些值是各种数字数据类型(short、int、double),一些字符串具有与之相关联的特定必需格式。我正在使用类似于以下代码块的内容来定义每个表列,使用SortStringConverter()或类似工具获取文本输入并将其转换为目标数据类型: TableColumn<InventoryLocation,Short> Cabinet

我试图在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()));
TableColumn CabinetColumn=新的TableColumn(“橱柜”);
细木工柱。设置最小宽度(50);
CabinetColumn.setCellValueFactory(新属性ValueFactory(“Cabinet”));
CabinetColumn.setCellFactory(TextFieldTableCell.forTableColumn(新的ShortStringConverter());
但是,我想首先防止用户输入任何无效数据。对于上面的示例,他们应该不能键入任何非数字字符。在我的应用程序的其他地方,在简单的文本字段中,我正在使用类似的东西来强制用户输入上的正则表达式匹配:

    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]", ""));
            }
        }
    });
quantity.textProperty().addListener(新的ChangeListener()){
@凌驾

public void已更改(observeValue您需要创建一个自定义tablecell-例如:

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);
        }

    }
}

}
公共类EditableBigDecimalTableCell扩展了TableCell{
私有文本字段文本字段;
私有整数minDecimals,最大小数;
/**
*这是默认值-我们将使用它作为小数点后2位
*/
公共可编辑BigDecimalTableCell(){
minDecimals=2;
最大小数=2;
}
/**
*当单元格需要具有不同于2个小数的行为时使用
*/
公共EditableBigDecimalTableCell(最小整数,最大整数){
minDecimals=min;
最大小数=最大值;
}
@凌驾
公开作废已启动IT(){
if(editableProperty().get()){
如果(!isEmpty()){
super.startEdit();
createTextField();
setText(空);
设置图形(文本字段);
textField.requestFocus();
}
}
}
@凌驾
公共作废取消编辑(){
super.cancelEdit();
setText(getItem()!=null?getItem().toPlainString():null);
设置图形(空);
}
@凌驾
公共void updateItem(BigDecimal项,布尔空){
super.updateItem(项,空);
if(空){
setText(空);
设置图形(空);
}否则{
if(isEditing()){
if(textField!=null){
setText(getString());
textField.selectAll();
}
setText(空);
设置图形(文本字段);
}否则{
setText(getString());
设置图形(空);
}
}
}
私有void createTextField(){
textField=新的textField();
setTextFormatter(新的DecimalTextFormatter(minDecimals,maxDecimals));
setText(getString());
textField.setOnAction(evt->{
if(textField.getText()!=null&&!textField.getText().isEmpty()){
NumberStringConverter nsc=新的NumberStringConverter();
数字n=nsc.fromString(textField.getText());
committedit(BigDecimal.valueOf(n.doubleValue());
}
});
textField.setMinWidth(this.getWidth()-this.getGraphicTextGap()*2);
textField.setOnKeyPressed((ke)->{
if(ke.getCode().equals(KeyCode.ESCAPE)){
取消编辑();
}
});
textField.setAlignment(右中位置);
此.设置对齐(位置居中\右侧);
}
私有字符串getString(){
NumberFormat nf=NumberFormat.getNumberInstance();
nf.setMinimumFractionDigits(minDecimals);
nf.setMaximumFractionDigits(最大小数);
return getItem()==null?“:nf.format(getItem());
}
@凌驾
公共作废承诺(大小数项){
if(isEditing()){
超级。承诺(项目);
}否则{
final TableView table=getTableView();
如果(表!=null){
TablePosition位置=新的TablePosition(getTableView(),
getTableRow().getIndex(),getTableColumn());
CellEditEvent editEvent=新的CellEditEvent(表格、位置、,
TableColumn.EditCommitteEvent(),项);
fireEvent(getTableColumn(),editEvent);
}
updateItem(项,false);
如果(表!=null){
表.编辑(-1,空);
}
}
}
}
使用一个格式化程序,它将阻止您不想要的值

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;
                }
            }
        }
    );
}
公共类DecimalTextFormatter扩展了TextFormatter{
私有静态DecimalFormat格式=新的DecimalFormat(“#.0;-#.0”);
公共小数文本格式化程序(int minDecimals,int maxDecimals){
超级(
新的StringConverter(){
@凌驾
公共字符串toString(数字对象){
if(object==null){
返回“”;
}
字符串格式=“0。”;
对于(int i=0;inumberColumn.setCellFactory(col -> new EditableBigDecimalTableCell<MyDTO>());