Java 在表格视图中编辑数字单元格

Java 在表格视图中编辑数字单元格,java,javafx,tableview,Java,Javafx,Tableview,我有一个TableView控件,它由几个列组成,包含不同的类型,包括Strings和Numbers。我一直在尝试为一个可编辑的数字单元格编写一个合适的回调函数,但由于我遇到了从空单元格到异常的各种问题,所以我在任何地方都做不到 我已经通读了,但这只涉及单元格中的字符串值。症结似乎是lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn())。这一行似乎是为文本字段而不是数字字段定制的 此外,我希望对输入的数字进行验证。要做到这一点

我有一个
TableView
控件,它由几个列组成,包含不同的类型,包括
String
s和
Number
s。我一直在尝试为一个可编辑的数字单元格编写一个合适的回调函数,但由于我遇到了从空单元格到异常的各种问题,所以我在任何地方都做不到

我已经通读了,但这只涉及单元格中的字符串值。症结似乎是
lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn())。这一行似乎是为文本字段而不是数字字段定制的

此外,我希望对输入的数字进行验证。要做到这一点,是否需要对
CellFactory
进行自定义回调?如果是这样,我如何开发一个接受数字类型并验证它们的回调

以下是我当前项目中的代码片段:

@FXML private TableView<BMIRecord> fxBMITable;
@FXML private TableColumn<BMIRecord, String> fxBMITableDate;
@FXML private TableColumn<BMIRecord, String> fxBMITableTime;
@FXML private TableColumn<BMIRecord, Number> fxBMITableHeight;
@FXML private TableColumn<BMIRecord, Number> fxBMITableWeight;
@FXML private TableColumn<BMIRecord, Number> fxBMITableBMI;

// ...

private void someFunc() {
    fxBMITable.setEditable(true);

    /* BMI table callback configuration */
    fxBMITableHeight.setCellValueFactory(new Callback<CellDataFeatures<BMIRecord, String>, ObservableValue<String>>() {
        public ObservableValue<String> call(CellDataFeatures<BMIRecord, String> p) {
            return new SimpleStringProperty(p.getValue().getDateString());
        }
    });

    /*
     * ERROR:
     * The method setCellFactory(Callback<TableColumn<BMIRecord,Number>,TableCell<BMIRecord,Number>>)
     * in the type TableColumn<BMIRecord,Number> is not applicable for the arguments
     * (Callback<TableColumn<Object,String>,TableCell<Object,String>>)
     */
    fxBMITableHeight.setCellFactory(TextFieldTableCell.forTableColumn());
    fxBMITableHeight.setOnEditCommit(new EventHandler<CellEditEvent<BMIRecord, Number>>() {
        @Override
        public void handle(CellEditEvent<BMIRecord, Number> t) {
            ((BMIRecord)t.getTableView().getItems().get(t.getTablePosition().getRow())).setHeight(t.getNewValue().doubleValue());
        }
    });
}
@FXML private TableView fxBMITable;
@FXML私有表列fxBMITableDate;
@FXML私有表列fxBMITableTime;
@FXML私有表列fxBMITableHeight;
@FXML私有表列fxBMITableWeight;
@FXML私有表列fxBMITableBMI;
// ...
私有void someFunc(){
fxBMITable.setEditable(true);
/*BMI表回调配置*/
fxBMITableHeight.setCellValueFactory(新回调(){
公共可观察值呼叫(CellDatap){
返回新的SimpleStringProperty(p.getValue().getDateString());
}
});
/*
*错误:
*方法setCellFactory(回调)
*在类型表中,列不适用于参数
*(回拨)
*/
fxbmitablehight.setCellFactory(TextFieldTableCell.forTableColumn());
fxBMITableHeight.setOnEditCommit(新的EventHandler(){
@凌驾
公共无效句柄(CellEditEvent t){
((BMIRecord)t.getTableView().getItems().get(t.getTablePosition().getRow()).setHeight(t.getNewValue().doubleValue());
}
});
}

感谢您事先提供的帮助。

TextFieldTableCell是类型参数化的,并且具有一个
stringConverter
属性,您可以使用该属性转换为字符串和所需类型

尝试以下方法:

TextFieldTableCell.<BMIRecord, Number>forTableColumn(new NumberStringConverter())
TextFieldTableCell.forTableColumn(新的NumberStringConverter())
NumberStringConverter有一些用于指定格式的附加构造函数,请参阅javadocs

下面是一个更完整的示例:

public class Person {

    public Person(String name0, int age0) {
        name = name0;
        age = age0;
    }
    public String name;
    public int age;
}        

TableView<Person> personTable = new TableView<>();

TableColumn<Person, Number> age = new TableColumn<>();

age.setCellValueFactory(new Callback<CellDataFeatures<Person, Number>, ObservableValue<Number>>() {
    @Override
    public ObservableValue<Number> call(CellDataFeatures<Person, Number> p) {
        return new SimpleIntegerProperty(p.getValue().age);
} 
});

age.setCellFactory(TextFieldTableCell.<Person, Number>forTableColumn(new NumberStringConverter()));
公共类人物{
公众人物(字符串名称0,整数0){
name=name0;
年龄=0岁;
}
公共字符串名称;
公共信息;
}        
TableView personTable=新建TableView();
TableColumn年龄=新建TableColumn();
age.setCellValueFactory(新回调(){
@凌驾
公共可观察值呼叫(CellDatap){
返回新的SimpleIntegerProperty(p.getValue().age);
} 
});
age.setCellFactory(TextFieldTableCell.forTableColumn(newnumberstringconverter());
不过,这并不能很好地工作,因为NumberStringConverter是如此的直截了当,实现得非常糟糕,以至于如果您碰巧在单元格中输入了字符串而不是数字,它只会向您抛出一个
ParseException

但是,实现您自己的字符串转换器应该相对简单,您也可以在其中执行一些简单的验证(例如,值应该在0到100之间)。

使用此选项

age.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
图书馆:

解决方案防止用户输入无效信息。仅允许使用0-9、彗差和点符号。您可以设置最小值和最大值

使用签名的方法:

TableViewUtils.setEditNumberCellFactory(
        TableColumn<T, K> cell,
        BiConsumer<T, Double> changeHandler, 
        String editControlHeader, 
        Double minAllowedValue,
        Double maxAllowedValue, 
        Function<T, Boolean> ignoreEdit)
TableViewUtils.setEditNumberCellFactory(
表列单元格,
双消费者变更处理程序,
字符串editControlHeader,
双最小值,
双最大允许值,
函数ignoreEdit)
模拟桌:

TableView<String> tableView = new TableView<>();
tableView.getItems().addAll("USA", "Canada", "Brazil");

TableColumn<String, String> country = new TableColumn<>("Country");
TableColumn<String, Integer> column = new TableColumn<>("Some value");

tableView.getColumns().add(country);
tableView.getColumns().add(column);

country.setCellValueFactory(
                data -> new SimpleObjectProperty<>(data.getValue()));
column.setCellValueFactory(
                data -> new SimpleObjectProperty<>(800));
TableView TableView=newtableview();
tableView.getItems().addAll(“美国”、“加拿大”、“巴西”);
TableColumn国家=新的TableColumn(“国家”);
TableColumn=新的TableColumn(“某些值”);
tableView.getColumns().add(国家/地区);
tableView.getColumns().add(column);
country.setCellValueFactory(
数据->新建SimpleObject属性(data.getValue());
column.setCellValueFactory(
数据->新建SimpleObject属性(800));
解决方案:

BiConsumer<String, Double> changeHandler = (item, newValue) -> {
        System.out.println("New value is " + newValue);
        // Your code
};

Function<String, Boolean> ignoreEdit = item -> item.equalsIgnoreCase("USA");

TableViewUtils.setEditNumberCellFactory(column, changeHandler, "New value:", 200.0, 800.0, ignoreEdit);
BiConsumer changeHandler=(item,newValue)->{
System.out.println(“新值为”+newValue);
//你的代码
};
函数ignoreEdit=item->item.equalsIgnoreCase(“美国”);
TableViewUtils.setEditNumberCellFactory(列,changeHandler,“新值:”,200.0,800.0,ignoreEdit);

谢谢你的建议,我尝试了你建议的方法,但是
部分被拒绝了。否则,我会得到一个类似于之前的错误:“type TableColumn中的方法setCellFactory(回调)不适用于参数(回调)”,对不起,我的Java有点生疏(我使用Scala)。我已经修正了语法,效果很好。感谢您花时间改进答案:)没有理由变得复杂。。。对于足够简单的上下文,转换器的使用非常简单。如果您认为您的库远远优于可用的默认支持(这个问题非常古老,多年来默认支持有所改进),那么您可能应该使用一个示例来证明这种优势:)我不认为我的库更好或更差。它解决了我的应用程序中的样板代码问题。应用程序有几个具有类似列的表。例如,BigDecimal列具有允许的最小值和最大值。顺便说一下,它可以防止用户输入无效的符号