gpt4 book ai didi

java - 如果解析失败,取消表格单元格编辑的规范方法

转载 作者:行者123 更新时间:2023-12-02 08:50:00 25 4
gpt4 key购买 nike

编辑:
在发现 this answer 后,我首先投票关闭作为重复项由 James_D 编写,它在 TextField 上设置 TextFormatter。但首先我发现(在 TableView 上下文中)方法 TextFieldTableCell.forTableColumn() 在启动时实际上并没有绘制 TextField编辑,而是一个 LabeledText,它不是 TextInputControl 的子类,因此没有 setTextFormatter()
其次,我想要一些以熟悉的方式运作的东西。我可能在我的回答中提出了“规范”的解决方案:让其他人判断。

<小时/>

这是 TableView 中的 TableColumn(全部 Groovy):

TableColumn<Person, String> ageCol = new TableColumn("Age")
ageCol.cellValueFactory = { cdf -> cdf.value.ageProperty() }

int oldAgeValue
ageCol.onEditStart = new EventHandler(){
@Override
public void handle( Event event) {
oldAgeValue = event.oldValue
}
}
ageCol.cellFactory = TextFieldTableCell.forTableColumn(new IntegerStringConverter() {
@Override
public Integer fromString(String value) {
try {
return super.fromString(value)
}
catch ( NumberFormatException e) {
// inform user by some means...
println "string could not be parsed as integer..."
// ... and cancel the edit
return oldAgeValue
}
}
})

摘自 Person 类:

public class Person {
private IntegerProperty age;
public void setAge(Integer value) { ageProperty().set(value) }
public Integer getAge() { return ageProperty().get() }
public IntegerProperty ageProperty() {
if (age == null) age = new SimpleIntegerProperty(this, "age")
return age
}
...

如果没有开始编辑Handler,当我输入无法解析为Integer NumberFormatException<的String 毫不奇怪地被抛出。但我还发现单元格中的数字随后被设置为 0,这可能不是期望的结果。

但是上面的解决方案让我觉得非常笨拙。

我查看了 ageColageCol.cellFactory (因为这些可以从 catch block 内部访问),但无法看到任何更好和明显的东西。我还可以看到,可以轻松获取 Callback (ageCol.cellFactory),但调用它需要参数 cdf,即 CellDataFeatures 实例,您必须再次将其存储在某个地方。

我确信 Swing 涉及某种 validator 机制:即,在从编辑器组件(通过某些委托(delegate)或其他东西)传输值之前,可以覆盖某些验证机制。但是这个 IntegerStringConverter 似乎起到了 validator 的作用,尽管似乎没有提供任何方法在验证失败时恢复到现有(“旧”)值。

有没有比我上面展示的机制更简单的机制?

最佳答案

编辑
NB 在克利奥帕特拉提出宝贵见解后有所改善。
编辑2
在意识到最好的事情是使用现有的默认编辑器并对其进行调整后,进行了彻底的检修。

<小时/>

我想我应该举一个 LocalDate 的例子,比 Integer 稍微有趣一点。给定以下类(class):

class Person(){ 
...
private ObjectProperty<LocalDate> dueDate;
public void setDueDate(LocalDate value) {
dueDateProperty().set(value);
}
public LocalDate getDueDate() {
return (LocalDate) dueDateProperty().get();
}
public ObjectProperty dueDateProperty() {
if (dueDate == null) dueDate = new SimpleObjectProperty(this, "dueDate");
return dueDate;
}

然后创建一个新的编辑器单元类,它与 TextFieldTreeTableCell(TreeTableCell 的子类)完全相同,默认情况下用于为TreeTableView 的表格单元格。但是,您不能真正对 TextFieldTreeTableCell 进行子类化,例如,其基本字段 textFieldprivate

因此,您从源代码中完整复制代码*(仅大约 30 行),然后调用它

class DueDateEditor extends TreeTableCell<Person, LocalDate> { 
...

然后,您必须创建一个新的 StringConverter 类,作为 LocalDateStringConverter 的子类。子类化的原因是,如果您不这样做,则在收到无效日期时不可能捕获由 fromString() 抛出的 DateTimeParseException:如果您使用 <不幸的是,JavaFX 框架捕获了它,但堆栈跟踪中没有任何涉及您自己的代码的帧。所以你这样做:

class ValidatingLocalDateStringConverter extends LocalDateStringConverter {
boolean valid;
LocalDate fromString(String value) {
valid = true;
if (value.isBlank()) return null;
try {
return LocalDate.parse(value);
} catch (Exception e) {
valid = false;
}
return null;
}
}

返回 DueDateEditor 类,然后重写 startEdit 方法,如下所示。注意,与 TextFieldTreeTableCell 类一样,textField 实际上是在您第一次编辑时延迟创建的。

@Override
void startEdit() {
if (! isEditable()
|| ! getTreeTableView().isEditable()
|| ! getTableColumn().isEditable()) {
return;
}
super.startEdit();

if (isEditing()) {
if (textField == null) {
textField = CellUtils.createTextField(this, getConverter());

// this code added by me
ValidatingLocalDateStringConverter converter = getConverter();
Callable bindingFunc = new Callable(){
@Override
Object call() throws Exception {
// NB the return value from this is "captured" by the editor
converter.fromString( textField.getText() );
return converter.valid? '' : "-fx-background-color: red;";
}
}
def stringBinding = Bindings.createStringBinding( bindingFunc, textField.textProperty() );
textField.styleProperty().bind( stringBinding );


}
CellUtils.startEdit(this, getConverter(), null, null, textField);
}
}

注意,不必费心去查找 CellUtils:这是包私有(private)的,有问题的包是 javafx.scene.control.cell。

要进行设置,请执行以下操作:

Callback<TreeTableColumn, TreeTableCell> dueDateCellFactory =
new Callback<TreeTableColumn, TreeTableCell>() {
public TreeTableCell call(TreeTableColumn p) {
return new DueDateEditor( new ValidatingLocalDateStringConverter() );
}
}
dueDateColumn.setCellFactory(dueDateCellFactory);

...结果是一个漂亮的响应式(Reactive)编辑器单元格:当包含无效日期时(可接受的模式yyyy-mm-dd;请参阅其他LocalDate.parse()) > 其他格式的变体)背景为红色,其他正常。输入有效日期可以无缝地进行。您还可以输入空的 String,该值将作为 null LocalDate 返回。

在上述情况下,按 Enter 键输入无效日期会将日期设置为 null。但是,使用 ValidatingLocalDateStringConvertervalid 字段来覆盖防止这种情况发生的事情(即强制您输入有效日期或取消编辑,例如通过 Escape)是微不足道的:

@Override
void commitEdit( LocalDate newDueDate ){
if( getConverter().valid )
super.commitEdit( newDueDate );
}
<小时/>

* 我在网上找不到这个。我从javafx源.jar文件中提取了javafx-controls-11.0.2-sources.jar

关于java - 如果解析失败,取消表格单元格编辑的规范方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60838502/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com