这个演员好吗?
Is this cast okay?
我有一个 EventHandler,我将其设置为事件的 event filter on TextFields. When I write the class, I get the source TextField by calling getSource() 并将其转换为 TextField。
EventHandler 的代码:
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 惯例,这个转换是否合适?我如何编写 class 才能使其只能用作 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 并添加您的方法,这样它就是类型安全的。
只是为了扩展我对 的评论:
不要使用继承来做一些你可以用组合更干净地做的事情。
我认为@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
.
Andy Turner 的回答提供了一种强大的通用方法,允许将事件处理程序仅添加到一种类型的 Node
。但是,对于否决对 TextField
(或其他文本输入控件)中文本的更改的特定情况,使用键事件处理程序的方法不是一个好方法,原因如下:
- 用户可以使用鼠标调出上下文菜单并在其中粘贴文本。这根本不涉及任何按键操作,因此不会调用您的处理程序。
- 您无法控制文本字段内部使用的按键事件类型。您是否使用
KEY_PRESSED
、KEY_RELEASED
或 KEY_TYPED
事件注册此过滤器?您确定文本字段内部使用的事件从一个 JavaFX 版本到下一个版本都保持不变吗?
- 您可能会无意中否决键盘快捷键,例如 Ctrl-C(用于复制)或 Ctrl-V(用于粘贴)等。 (如果你不否决 "paste" 的快捷方式,你就允许用户粘贴无效文本的另一个漏洞......)。同样,JavaFX 的未来版本可能会引入额外的快捷方式,这几乎不可能证明您的功能。
为了完整起见,此特定用例的首选方法如下:
使用 TextFormatter
,这是支持的机制,用于否决或修改文本输入控件的文本条目(以及提供格式化或解析控件中文本的机制)。您可以通过在独立 class:
中实现过滤器来使其可重用
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)));
我有一个 EventHandler,我将其设置为事件的 event filter on TextFields. When I write the class, I get the source TextField by calling getSource() 并将其转换为 TextField。
EventHandler 的代码:
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 惯例,这个转换是否合适?我如何编写 class 才能使其只能用作 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 并添加您的方法,这样它就是类型安全的。
只是为了扩展我对
不要使用继承来做一些你可以用组合更干净地做的事情。
我认为@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
.
Andy Turner 的回答提供了一种强大的通用方法,允许将事件处理程序仅添加到一种类型的 Node
。但是,对于否决对 TextField
(或其他文本输入控件)中文本的更改的特定情况,使用键事件处理程序的方法不是一个好方法,原因如下:
- 用户可以使用鼠标调出上下文菜单并在其中粘贴文本。这根本不涉及任何按键操作,因此不会调用您的处理程序。
- 您无法控制文本字段内部使用的按键事件类型。您是否使用
KEY_PRESSED
、KEY_RELEASED
或KEY_TYPED
事件注册此过滤器?您确定文本字段内部使用的事件从一个 JavaFX 版本到下一个版本都保持不变吗? - 您可能会无意中否决键盘快捷键,例如 Ctrl-C(用于复制)或 Ctrl-V(用于粘贴)等。 (如果你不否决 "paste" 的快捷方式,你就允许用户粘贴无效文本的另一个漏洞......)。同样,JavaFX 的未来版本可能会引入额外的快捷方式,这几乎不可能证明您的功能。
为了完整起见,此特定用例的首选方法如下:
使用 TextFormatter
,这是支持的机制,用于否决或修改文本输入控件的文本条目(以及提供格式化或解析控件中文本的机制)。您可以通过在独立 class:
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)));