I had some little sample I wanted to write where I had a TextField that restricted input. Maybe somebody else out there has already figured out how to do this elegantly, but I hadn’t and thought it would be worth a small post to demonstrate the technique.
Within the TextInputControl is a Content, which actually models the TextInputControl’s content. So for example, this is where we strip out newlines and such if you paste a String into a TextField that contains such characters, but in TextArea we allow those sorts of modifications. There is a protected getContent() method, so in theory a subclass of TextInputControl can manipulate the content directly, although in the case of TextField, it does not.
In fact, the only places in all the code that actually modify the TextField’s text is in the replaceText and replaceSelection methods defined on TextInputControl. So all you have to do is subclass TextField and override these two methods.
field = new TextField() { @Override public void replaceText(int start, int end, String text) { // If the replaced text would end up being invalid, then simply // ignore this call! if (!text.matches("[a-z]")) { super.replaceText(start, end, text); } } @Override public void replaceSelection(String text) { if (!text.matches("[a-z]")) { super.replaceSelection(text); } } };
In the future we may want to add a more specific method (maybe called “accept” which takes the proposed new string after the modification) so that in the off chance that TextField or TextInputControl ends up modifying the content from some additional methods beyond these two, you could still have a reliable way to reject invalid input. However for the time being, this should work just fine!
I think that JavaFX2 should take some design cues from Qt. It is an established GUI framework with many users and developers including KDE, the Linux desktop environment. With KDE using Qt, it receives a lot of real world use and some great features come out of this.
In Qt, QLineEdit (One line text boxes), have an input mask. This mask and provide a template to what can be entered into the box. It provides visual feedback for the user as well.
There is also the QValidator which has a few useful subclasses such as QIntValidator, QDoubleValidator and QRegexValidator which can be applied to various controls to validate the control’s input.
I’m really rooting for JavaFX2. I just hope that the developers take a look at Qt and see all that is provided. I’d love to move away from Qt/C++, but I don’t think I could leave if JavaFX doesn’t provide the functionality that makes Qt such an enjoyable experience to program in. (Minus dealing with C++).
Hi Tamul,
I think regex validation is fine for URL & email (although it is tricky to craft a good regex for email). Either a masked input or regex input is not suitable for phone numbers, dates, or money since the format is both locale dependent as well as being quite complicated requiring logic beyond what a regex or input mask can handle well (see the library Google uses for phone numbers for examples of the complexity).
In Swing, that kind of task can be achieved by registering a custom DocumentListener in a JTextField. Any chance we can see something like that in JavaFX?
I am thinking of something more along the lines of a callback property on TextField, like setInputFilter(new Callback() {…}); or something, but not sure.
What about in the case when a user copy and pastes into the TextField?
Should work, are you seeing a problem when pasting?
Richard,
Apologies for the time it took to reply, I forgot about this comment 🙂
I am having issues when copying and pasting into the textfield using the method you described in the OP.
I select the TextField, paste a “aaa” into it and then tab out of the Text Field and the “aaa” remains.
The only change I have made to your code is the TextField I have declared is final.
If you would also like to restrict the number of characters allowed you can handle the maximum characters on the TextField by doing…
final int maxChars = 10;
final String restictTo = “[a-zA-z0-9\\s]*”;
final TextField tf = new TextField() {
@Override
public void replaceText(int start, int end, String text) {
if (matchTest(text)) {
super.replaceText(start, end, text);
}
}
@Override
public void replaceSelection(String text) {
if (matchTest(text)) {
super.replaceSelection(text);
}
}
private boolean matchTest(String text) {
return text.isEmpty() || (text.matches(restictTo) && getText().length() < maxChars);
}
};
Hi,
This information was very helpful to me on my studies about JavaFX. But I identified a problem during the tests.
When I use field.setText(String) called by another method, none of these control methods were called. Well, if I need to prevent an alphabetic input by this way, I cannot treat because setText is a final method.
Do I have other way to treat it using overriding methods? Or I really need to create a new method like setText to control the input?
Could I consider this behavior as a bug?
You can copy a wrong values from another field to the validatedField and the validation doesnt recognize it.
You may be interested in this issue: RT-30881 where I’m making a proper API for this instead of overriding just these methods. These methods also didn’t work correctly with undo / redo.
hi , the best way is:
txt_PuissanceDepart.addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler() {
@Override
public void handle(KeyEvent e ) {
if(e.getCode().isDigitKey()){ /* Letters only */
txt_PuissanceDepart.deletePreviousChar();
}
}
});
txt_PuissanceDepart.addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler() {
@Override
public void handle(KeyEvent e ) {
if(e.getCode().isLetterKey()){ /* Digits only */
txt_PuissanceDepart.deletePreviousChar();
}
}
});
best of luck.
@FXML
private TextField txt_Numeric;
@FXML
private TextField txt_Letters;
@Override
public void initialize(URL url, ResourceBundle rb) {
/* add Event Filter to your TextFields **************************************************/
txt_Numeric.addEventFilter(KeyEvent.KEY_TYPED , numeric_Validation(10));
txt_Letters.addEventFilter(KeyEvent.KEY_TYPED , letter_Validation(10));
}
/* Numeric Validation Limit the characters to maxLengh AND to ONLY DigitS *************************************/
public EventHandler numeric_Validation(final Integer max_Lengh) {
return new EventHandler() {
@Override
public void handle(KeyEvent e) {
TextField txt_TextField = (TextField) e.getSource();
if (txt_TextField.getText().length() >= max_Lengh) {
e.consume();
}
if(e.getCharacter().matches("[0-9.]")){
if(txt_TextField.getText().contains(".") && e.getCharacter().matches("[.]")){
e.consume();
}else if(txt_TextField.getText().length() == 0 && e.getCharacter().matches("[.]")){
e.consume();
}
}else{
e.consume();
}
}
};
}
/****************************************************************************************/
/* Letters Validation Limit the characters to maxLengh AND to ONLY Letters *************************************/
public EventHandler letter_Validation(final Integer max_Lengh) {
return new EventHandler() {
@Override
public void handle(KeyEvent e) {
TextField txt_TextField = (TextField) e.getSource();
if (txt_TextField.getText().length() >= max_Lengh) {
e.consume();
}
if(e.getCharacter().matches("[A-Za-z]")){
}else{
e.consume();
}
}
};
}
/****************************************************************************************/
Since this post is still quite popular in Google, it might be worth mentioning that since JavaFX 8u40 you can set a TextFormatter object on a TextField to restrict or modify user input.
See https://uwesander.de/?p=203 for an example.
when invoking the requiredField2.eval(); in the save class it is geeting the error
i want to replace some part of text with new textfield in javafx. for example: my name is $$$$$$/&&&&&&&. i want to rplace these special character with editable textfield.
please help me.