Recommended way to restrict input in JavaFX textfield

Nikhil picture Nikhil · Mar 25, 2013 · Viewed 18.4k times · Source

It may seem the question is the duplicate of this. But my question is i have developed a integer textfield in JavaFX by two ways. The code is given below

public class FXNDigitsField extends TextField
{
private long m_digit;
public FXNDigitsField()
{
    super();
}
public FXNDigitsField(long number)
{
    super();
    this.m_digit = number;
    onInitialization();
}

private void onInitialization()
{
    setText(Long.toString(this.m_digit));
}

@Override
public void replaceText(int startIndex, int endIndex, String text)
{
    if (text.matches(Constants.DIGITS_PATTERN) || text.equals(Constants.EMPTY_STRING)) {
        super.replaceText(startIndex, endIndex, text);
    }
}

@Override
public void replaceSelection(String text)
{
    if (text.matches(Constants.DIGITS_PATTERN) || text.equals(Constants.EMPTY_STRING)) {
        super.replaceSelection(text);
    }
}
}

And the second way is by adding an event Filter.

The code snippet is given.

 // restrict key input to numerals.
this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
  @Override public void handle(KeyEvent keyEvent) {
    if (!"0123456789".contains(keyEvent.getCharacter())) {
      keyEvent.consume();
    }
  }
});

My question is which is the slandered way to do this? Can anyone help me to pick up the right?

Answer

gmatagmis picture gmatagmis · Oct 31, 2014

The best way to add validation in TextField is a 3rd way. This method lets TextField finish all processing (copy/paste/undo safe). It does not require you to extend the TextField class. And it allows you to decide what to do with new text after every change (to push it to logic, or turn back to previous value, or even to modify it).

// fired by every text property changes
textField.textProperty().addListener(
  (observable, oldValue, newValue) -> {
    // Your validation rules, anything you like
    // (! note 1 !) make sure that empty string (newValue.equals("")) 
    //   or initial text is always valid
    //   to prevent inifinity cycle
    // do whatever you want with newValue

    // If newValue is not valid for your rules
    ((StringProperty)observable).setValue(oldValue);
    // (! note 2 !) do not bind textProperty (textProperty().bind(someProperty))
    //   to anything in your code.  TextProperty implementation
    //   of StringProperty in TextFieldControl
    //   will throw RuntimeException in this case on setValue(string) call.
    //   Or catch and handle this exception.

    // If you want to change something in text
    // When it is valid for you with some changes that can be automated.
    // For example change it to upper case
    ((StringProperty)observable).setValue(newValue.toUpperCase());
  }
);