这个演员好吗?

时间:2017-05-09 20:54:28

标签: java javafx event-handling conventions

我有一个EventHandler,我在TextFields上设置为event filter。当我编写类时,我通过在事件上调用getSource()并将其转换为TextField来获取源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约定进行转换?除了作为TextField的事件过滤器之外,我怎样才能编写类以便它可以在任何地方使用?

3 个答案:

答案 0 :(得分:4)

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

  1. 用户可以使用鼠标调出上下文菜单并粘贴文本。这根本不涉及任何按键操作,因此不会调用您的处理程序。
  2. 您无法控制文本字段在内部使用哪种类型的键事件。您是否在KEY_PRESSEDKEY_RELEASEDKEY_TYPED个活动中注册了此过滤条件?您确定文本字段内部使用的事件从一个JavaFX版本到下一个版本将保持不变吗?
  3. 您可能会无意中否决键盘快捷键,例如Ctrl-C(用于复制)或Ctrl-V(用于粘贴)等。 (如果您没有否决“粘贴”的快捷方式,则允许用户粘贴无效文本的另一个漏洞...)。同样,未来的JavaFX版本可能会引入额外的快捷方式,这几乎不可能证明您的功能。
  4. 为完整起见,此特定用例的首选方法如下:

    使用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)));
    

答案 1 :(得分:3)

只是扩展我对@MaxPower's answer的评论:

不要使用继承来做一些你可以更加干净地使用合成的东西。

我认为@ 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

答案 2 :(得分:1)

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

如果你知道每次调用这段代码,它都将来自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并添加您的方法,然后它的类型安全。