I am creating some forms and I need to create masks and validation for some fields.
Is it implemented in anyway in JavaFX?
I am creating some forms and I need to create masks and validation for some fields.
Is it implemented in anyway in JavaFX?
My example of the mask.
Using:
<MaskField mask="+7(DDD)DDD-DDDD"/>
<MaskField mask="AA DDD AAA" placeholder="__ ### ___"/>
etc
Restricting input from Richard's fxexperience post:
TextField 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);
}
}
};
If you want to create your use a mask and create your own control, take a look at Richard's MoneyField, which also includes a sample project and source. Along the same lines there are controls to restict input to Integers, Doubles or formatted web colors (e.g. #rrggbb) in the fxexperience repository. All of these follow a common theme where they subclass Control, provide some properties to be get and set which define the public interface and then also define a private backing skin which handles rendering of the UI based on the values set through the public interface.
I had the same needs. I created this field, called it SpecialTextField, and pushed into GitHub. Example also there. Hope this help.
NOTE: this only works correctly with JRE 1.8.0_25 or lower. With JRE 1.8.0_48 or 0_51, the caret position is always set to 0 after each character input.
No, this is not implemented in standard JavaFX. You need to use some library or do it yourself.
This is my implementation of static mask for text fields. It works for date, phone and other types of static masks:
/**
* Adds a static mask to the specified text field.
* @param tf the text field.
* @param mask the mask to apply.
* Example of usage: addMask(txtDate, " / / ");
*/
public static void addMask(final TextField tf, final String mask) {
tf.setText(mask);
addTextLimiter(tf, mask.length());
tf.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
String value = stripMask(tf.getText(), mask);
tf.setText(merge(value, mask));
}
});
tf.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(final KeyEvent e) {
int caretPosition = tf.getCaretPosition();
if (caretPosition < mask.length()-1 && mask.charAt(caretPosition) != ' ' && e.getCode() != KeyCode.BACK_SPACE && e.getCode() != KeyCode.LEFT) {
tf.positionCaret(caretPosition + 1);
}
}
});
}
static String merge(final String value, final String mask) {
final StringBuilder sb = new StringBuilder(mask);
int k = 0;
for (int i = 0; i < mask.length(); i++) {
if (mask.charAt(i) == ' ' && k < value.length()) {
sb.setCharAt(i, value.charAt(k));
k++;
}
}
return sb.toString();
}
static String stripMask(String text, final String mask) {
final Set<String> maskChars = new HashSet<>();
for (int i = 0; i < mask.length(); i++) {
char c = mask.charAt(i);
if (c != ' ') {
maskChars.add(String.valueOf(c));
}
}
for (String c : maskChars) {
text = text.replace(c, "");
}
return text;
}
public static void addTextLimiter(final TextField tf, final int maxLength) {
tf.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
if (tf.getText().length() > maxLength) {
String s = tf.getText().substring(0, maxLength);
tf.setText(s);
}
}
});
}
See also: JavaFX 2.2 TextField maxlength
Supported by current javafx-2 platform by default - No, but go through this link , it has many insights and sample code for Form validation in javaFX
public class NumberTextField extends TextField {
private int maxLenght;
public NumberTextField(int maxLenght) {
super();
this.maxLenght = maxLenght;
}
@Override
public void replaceText(int start, int end, String text) {
if (validate(text)) {
super.replaceText(start, end, text);
}
}
@Override
public void replaceSelection(String text) {
if (validate(text)) {
super.replaceSelection(text);
}
}
private boolean validate(String text) {
if (this.getText() != null) {
}
boolean status = ("".equals(text) || text.matches("[0-9]"));
if (this.getText() == null) {
return status;
} else {
return (status && this.getText().length() < maxLenght);
}
}
}
In some cases I would validate the text property:
myTextField
.textProperty()
.addListener(
(obs, oldVal, newVal) ->
{
if(!newVal.matches("\\d+"))
textField.setText(oldV);
});
Unlucky: textField.setText(oldV);
will enter the same function again, testing unnecessarily if oldVal matches.
If the TextField becomes a value that doesn't matches before this listener is added to the TextField, enter a not matching new value will cause a loop!!!
To avoid this, it will be safer to write:
String acceptableValue = "0";
myTextField
.textProperty()
.addListener(
(obs, oldVal, newVal) ->
{
if(!newVal.matches("\\d+"))
textField.setText(oldVal.matches("\\d+") ? oldV : acceptableValue);
});
I wrote a class that extends the TextField and apply the mask.
package com.model;
import java.text.NumberFormat;
import java.util.Locale;
/**
* ATENTION
* DO NOT FORGUET TO IMPORT IN FXML
* <?import com.view.TextFieldMoney?>
*
* */
import javafx.scene.control.TextField;
public class TextFieldMoney extends TextField {
private int maxlength;
private String valor = "";
public TextFieldMoney() {
this.maxlength = 11;
}
public void setMaxlength(int maxlength) {
this.maxlength = maxlength;
}
@Override
public void replaceText(int start, int end, String text) {
// Delete or backspace user input.
if (getText() == null || getText().equalsIgnoreCase("")) {
valor = "";
}
if (text.equals("")) {
super.replaceText(start, end, text);
} else{
text = text.replaceAll("[^0-9]", "");
valor += text;
super.replaceText(start, end, text);
if (!valor.equalsIgnoreCase(""))
setText(formata(valor));
}
}
@Override
public void replaceSelection(String text) {
// Delete or backspace user input.
if (text.equals("")) {
super.replaceSelection(text);
} else if (getText().length() < maxlength) {
// Add characters, but don't exceed maxlength.
// text = MascaraFinanceira.show(text);
if (text.length() > maxlength - getText().length()) {
// text = MascaraFinanceira.show(text);
text = text.substring(0, maxlength - getText().length());
}
super.replaceSelection(text);
}
}
/*
*Return the number without money mask
**/
public String getCleanValue(){
String cleanString = getText().replaceAll("[^0-9]", "");
Double cleanNumber = new Double(cleanString);
return String.valueOf(cleanNumber/100);
}
private String formata(Double valor) {
Locale locale = new Locale("pt", "BR");
NumberFormat nf = NumberFormat.getInstance(locale);
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
return nf.format(valor);
}
public String formata(String valor) {
double v = new Double(valor);
return formata(v/100);
}
}
And in the FXML where is
<TextField fx:id="valorTextField" GridPane.columnIndex="2" GridPane.rowIndex="2" />
put
<TextFieldMoney fx:id="valorTextField" GridPane.columnIndex="2" GridPane.rowIndex="2" />