这个演员表可以吗?



我有一个事件处理程序,我将其设置为文本字段上的事件过滤器。当我编写类时,我通过在事件上调用 getSource() 并将其强制转换为 TextField 来获取源 TextField。

事件处理程序的代码:

public class NumberFilter implements EventHandler<KeyEvent> {
public final int maxLength;
public NumberFilter(int maxLength) {
this.maxLength = maxLength;
}
@Override
public void handle(KeyEvent event) {
TextField textField = (TextField) event.getSource(); //<-- is this cast okay?
//consume event if there is too much text or the input isn't a number.
if (textField.getText().length() >= maxLength || !event.getCharacter().matches("[0-9]")) {
event.consume();
}
}
}

按照标准的 java 约定,这个强制转换可以吗?如何编写类,使其除了用作 TextField 的事件筛选器之外不能在任何地方使用?

Andy Turner的回答提供了一种强大的通用方法,允许将事件处理程序仅添加到一种类型的Node中。但是,对于否决对TextField(或其他文本输入控件)中的文本进行更改的特定情况,使用键事件处理程序的方法并不好,原因如下:

  1. 用户可以使用鼠标调出上下文菜单并粘贴文本。这根本不涉及任何按键,因此不会调用您的处理程序。
  2. 您无法控制文本字段在内部使用哪种类型的键事件。是否向KEY_PRESSEDKEY_RELEASEDKEY_TYPED事件注册此筛选器?您确定文本字段内部使用的事件从一个 JavaFX 发行版到下一个发行版将保持不变吗?
  3. 您可能会无意中否决键盘快捷键,例如 Ctrl-C(用于复制)或 Ctrl-V(用于粘贴)等。(如果你不否决"粘贴"的快捷方式,你就允许用户粘贴无效文本的另一个漏洞......同样,JavaFX 的未来版本可能会引入额外的快捷方式,而这些快捷方式几乎不可能证明您的功能。

为了完整起见,此特定用例的首选方法如下:

使用TextFormatter,这是用于否决或修改文本输入控件的文本输入(以及提供格式化或分析控件中文本的机制)的受支持机制。您可以通过在独立类中实现过滤器来使其可重用:

public class NumberFilter implements UnaryOperator<TextFormatter.Change> {
private final Pattern pattern ;
public NumberFilter(int maxLength) {
pattern = Pattern.compile("[0-9]{0,"+maxLength+"}");
}
@Override
public TextFormatter.Change apply(TextFormatter.Change c) {
String newText = c.getControlNewText() ;
if (pattern.matcher(newText).matches()) {
return  c ;
} else {
return null ;
}
}
}

现在你可以做到

TextField textField = new TextField();
textField.setTextFormatter(new TextFormatter<String>(new NumberFilter(5)));

只是为了扩展我对@MaxPower答案的评论:

不要使用继承来做一些你可以更干净地用组合做的事情。

我认为在这种情况下,@James_D的方法更好;但是如果通常您想要一个只能添加到特定类型字段中的EventHandler,请通过您的 API 强制执行:

public class NumberFilter implements EventHandler<KeyEvent> {
public static void addTo(int maxLength, TextField textField) {
textField.addEventHandler(new NumberFilter(maxLength));  
}
private NumberFilter(int maxLength) {
// Private ctor means that you can't just create one of these
// however you like: you have to create it via the addTo method.
}
// Now casting in the handle() method is safe.
}

这样,创建NumberFilter的唯一方法是通过addTo方法;这需要您将其添加到TextField中。

强制转换是一种告诉编译器你知道的比它知道的更多的方式。

如果你知道每次调用这段代码时,它都会来自TextField,那就没关系了。 否则,我会做

try {
TextField textField = (TextField) event.getSource();
//Do Stuff
}
catch(ClassCastException e) {
//handle the error
}

或者如果你想要更多的类型安全性

if(event.getSource() instanceof TextField) {
TextField textField = (TextField) event.getSource();
}

或者更好

public class MyTextField extends TextField implements EventHandler<KeyEvent> {
} 

然后放置使用它而不是 TextField 并添加您的方法,那么它是类型安全的。

相关内容

  • 没有找到相关文章

最新更新