gpt4 book ai didi

javafx - 格式化文本字段

转载 作者:行者123 更新时间:2023-12-02 04:01:38 25 4
gpt4 key购买 nike

我正在尝试创建一个 TextField其内容通过模板进行验证。为此,我创建了一个 TextFormatter我向其传递 StringConverter .

但是,我确实注意到使用 StringConverter<String> 的一个奇怪的事情。当我输入无效数据并且该字段失去焦点时,它不会清除其内容(仅在后续聚焦后才清除它)。作为比较,当我使用 StringConverter<LocalTime> 时这个问题没有被注意到。

如果我捕获焦点的变化并验证数据,问题就解决了,但我想知道为什么这两种情况下的验证存在差异。

public class Sample extends Application {


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

@Override
public void start(Stage primaryStage) {
TextField fieldA = new TextField();
fieldA.setPromptText("00000");
fieldA.setTextFormatter(new TextFormatter<>(new StringConverter<String>() {
@Override
public String toString(String object) {
if(object == null) return "";
return object.matches("[0-9]{5}") ? object : "";
}

@Override
public String fromString(String string) {
if(string == null) return null;
return string.matches("[0-9]{5}") ? string : null;
}
}));

// fieldA.focusedProperty().addListener((observable, oldValue, newValue) -> {
// if(!fieldA.textProperty().getValueSafe().matches("[0-9]{5}")) {
// fieldA.setText(null);
// }
// });

TextField fieldB = new TextField();
fieldB.setPromptText("HH:MM:SS");
fieldB.setTextFormatter(new TextFormatter<>(new StringConverter<LocalTime>() {
@Override
public String toString(LocalTime object) {
if(object == null) return "";
return object.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

@Override
public LocalTime fromString(String string) {
if(string == null) return null;
return LocalTime.parse(string, DateTimeFormatter.ofPattern("HH:mm:ss"));
}
}));

VBox vBox = new VBox(fieldA, fieldB);
vBox.setSpacing(5);

primaryStage.setScene(new Scene(vBox));
primaryStage.show();
}
}

ps:注意,目的不是创建TextField只能接受 5 个号码。这只是一个例子。

最佳答案

我找到了行为差异的原因。主要问题是更新控件是通过绑定(bind)valueProperty来完成的(在 TextFormatter 中)与 textProperty (在 TextField 中)。因为更改通知全部Property仅当包装器的值发生更改时,对象才会饱和,连续的 null 提交会导致一次性通知。

使用 StringConverter<LocalTime> 时的不同行为是因为LocalTime::parse()抛出 DateTimeParseException无效格式异常。这又导致了一个新的valueProperty正在设置的值,并设置为先前的有效控制值。

这是 TextFormatter 的具体片段这是造成这种行为的原因。

void updateValue(String text) {
if (!value.isBound()) {
try {
V v = valueConverter.fromString(text);
setValue(v);
} catch (Exception e) {
updateText(); // Set the text with the latest value
}
}
}

问题的解决方案是实现 StringConverter::fromString如果值无效,则不应返回 null,而应抛出未经检查的异常。

public class Sample extends Application {


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

@Override
public void start(Stage primaryStage) {
TextField fieldA = new TextField();
fieldA.setPromptText("00000");
fieldA.setTextFormatter(new TextFormatter<>(new StringConverter<String>() {
@Override
public String toString(String object) {
if(object == null) return "";
return object.matches("[0-9]{5}") ? object : "";
}

@Override
public String fromString(String string) {
if(string == null)
throw new RuntimeException("Value is null");

if(string.matches("[0-9]{5}")) {
return string;
}

throw new RuntimeException("Value not match");
}
}));


TextField fieldB = new TextField();
fieldB.setPromptText("HH:MM:SS");
fieldB.setTextFormatter(new TextFormatter<>(new StringConverter<LocalTime>() {
@Override
public String toString(LocalTime object) {
if(object == null) return "";
return object.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

@Override
public LocalTime fromString(String string) {
if(string == null) return null;
return LocalTime.parse(string, DateTimeFormatter.ofPattern("HH:mm:ss"));
}
}));


VBox vBox = new VBox(fieldA, fieldB);
vBox.setSpacing(5);

primaryStage.setScene(new Scene(vBox));
primaryStage.show();
}
}

关于javafx - 格式化文本字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57888193/

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