I m using the the focus event listener to implement a placeholder solution for all JTextComponents (JTextField, JTextArea ...) my implementation is as below
public class PlaceHolderDecorator {
public static void decorate(JTextField field, String placeHoldingText) {
field.setForeground(Color.GRAY);
field.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (field.getText().equals(placeHoldingText)) {
field.setText("");
field.setForeground(Color.BLACK);
}
}
@Override
public void focusLost(FocusEvent e) {
if (field.getText().isEmpty()) {
field.setForeground(Color.GRAY);
field.setText(placeHoldingText);
}
}
});
}
public static void decorate(JTextField field, String placeHoldingText,Color placeHolderColor,Color textColor) {
field.setForeground(placeHolderColor);
field.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (field.getText().equals(placeHoldingText)) {
field.setText("");
field.setForeground(textColor);
}
}
@Override
public void focusLost(FocusEvent e) {
if (field.getText().isEmpty()) {
field.setForeground(placeHolderColor);
field.setText(placeHoldingText);
}
}
});
}
final public static int DATE_FIELD_P = 10;
final public static int PHONE_FIELD_P = 14;
public static void decorate(JFormattedTextField field,String placeHoldingText,Color placeHolderColor,Color textColor,int checkFieldProperty){
field.setForeground(placeHolderColor);
final JFormattedTextField.AbstractFormatterFactory formatterFactory = field.getFormatterFactory();
field.setFormatterFactory(null);
field.setText(placeHoldingText);
field.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (field.getText().equals(placeHoldingText)) {
field.setText("");
field.setForeground(textColor);
field.setFormatterFactory(formatterFactory);
}
}
@Override
public void focusLost(FocusEvent e) {
if (field.getText().trim().length()!=checkFieldProperty ) {
field.setFormatterFactory(null);
field.setText("");
}
if (field.getText().isEmpty()) {
field.setFormatterFactory(null);
field.setForeground(placeHolderColor);
field.setText(placeHoldingText);
}
}
});
}
}
to use my place holder tool I do the following
final Color writingColor = new Color(45, 45, 45);
final Color holdingColor = new Color(127, 127, 127);
PlaceHolderDecorator.decorate(jFTFDateDepot, "Date dépot du dossier", holdingColor, writingColor, PlaceHolderDecorator.DATE_FIELD_P);
PlaceHolderDecorator.decorate(jtfNom, "Nom", holdingColor, writingColor);
this way when a focus occurs the place holder will be shown, after this I needed to creat a validation mechanisme for my inputs so I got the idea to check my field like this :
public class RequiredFieldValidator {
final private List<JTextComponent> components;
private ErrorDialog dialog;
public RequiredFieldValidator() {
components = new ArrayList<>();
}
public void add(JTextComponent jTextComponent) {
components.add(jTextComponent);
}
public boolean validate() {
for (final JTextComponent component : components) {
String placeHolder = component.getText();
System.out.println("placeholder : " + placeHolder);
component.requestFocus();
if (component.getText().trim().isEmpty()) {
System.out.println("validation started");
dialog = new ErrorDialog(null, true);
dialog.showErrorDialog("Veuillez remplir le champs " + placeHolder + " obligatoir");
component.requestFocus();
return false;
}
}
return true;
}
}
as you see in my code to get rid of the place holding text I do request a focus, where the text will be empty if the user haven't put any text if not the input of the user will remain
I do use this field validator like this
I register my required fields in the init section
fieldValidator = new RequiredFieldValidator();
fieldValidator.add(jFTFDateDepot);
fieldValidator.add(jFTFDateNaissance);
fieldValidator.add(jFTFNumTel);
fieldValidator.add(jtfLieuNaissance);
fieldValidator.add(jtfNom);
fieldValidator.add(jtfPrenom);
then I fire the validation process on the create event.
My issue in this code is that before running I was expecting this LIKE sequence diagram on the create event
Getting current component >> requestFocus() >> fire place holding event >> do processing on the text of the component >> return to validation >> get the processed text >> if empty show alert >> if not loop to next component
but I was surprised to see that my request focus listener on the current component is firing later on the swing thread dispatcher
please how to make this thread safe, I need to fire the focus listener before the get text of the validation.