0

I want a textfield that enables the user to enter a date following a specific pattern, and I want this date to be returned as soon as it is typed and valid, that is without waiting that the user press return on the textfield to process it. Also I'm adding visual hints whether the entered date is correct (changing the background color of the textfield).

Here is an SSC-not-that-correct example

package gui.date;

import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

public class DateEditor extends JFormattedTextField
{

    public DateEditor()
    {
        this(null, null);
    }

    public DateEditor(Date d)
    {
        this(d, null);
    }

    public DateEditor(Date d, String pattern)
    {
        super(new SimpleDateFormat(pattern));
        setValue(d);
        setFocusLostBehavior(JFormattedTextField.PERSIST);

        final Color origBgdColor = getBackground();
        final Color wrongInputColor = new Color(0.8f, .0f, .0f);
        final Color missingInputColor = new Color(1f, 1f, .65f);
        if(d == null)
        {
            setColumns(10);
            setBackground(missingInputColor);
        }
        addCaretListener(new CaretListener()
        {

            @Override
            public void caretUpdate(CaretEvent e)
            {
                if(isEditValid())
                {
                    try
                    {
                        setBackground(origBgdColor);
                        commitEdit();
                    }
                    catch(ParseException ex)
                    {
                        ex.printStackTrace();
                    }
                }
                else
                {
                    try
                    {
                        String text = getText();
                        if(text.isEmpty())
                            setBackground(missingInputColor);
                        else
                            setBackground(wrongInputColor);
                    }
                    catch(NullPointerException ex)
                    {
                        setBackground(missingInputColor);
                    }
                }
            }
        });
    }

    public Date getDate()
    {
        return (Date)getValue();
    }

    public void setDate(Date d)
    {
        setValue(d);
    }

    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {

            @Override
            public void run()
            {
                final Date[] date = new Date[] { null }; // the date entered by the user should be filled here as soon as it is a valid date
                final String pattern = "dd/MM/YYYY";
                final SimpleDateFormat fm = new SimpleDateFormat(pattern);

                JButton b = new JButton(new AbstractAction("Print value")
                {

                    @Override
                    public void actionPerformed(ActionEvent e)
                    {
                        try
                        {
                            System.out.println(fm.format(date[0]));
                        }
                        catch(NullPointerException ex)
                        {
                            System.out.println("No date set yet");
                        }
                    }
                });
                final DateEditor d = new DateEditor(null, pattern);
                d.addPropertyChangeListener("value", new PropertyChangeListener()
                {

                    @Override
                    public void propertyChange(PropertyChangeEvent evt)
                    {
                        if(evt.getSource().equals(d))
                        {
                            date[0] = d.getDate();
                        }
                    }
                });
                final JFrame f = new JFrame(getClass().getName());
                Container c = f.getContentPane();
                c.setLayout(new FlowLayout());
                c.add(b);
                c.add(d);
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setVisible(true);
            }
        });
    }
}

If you try it out you will see several errors: 1/ The pattern I specified seems not to be applied by the FormattedText, such that an entered valid date can be transformed into a different date when I press enter

2/ ParseException keeps being raised when calling commitEdit in the CaretListener, despite the fact that I first check isEditValid()!

Thx for your help.

remi
  • 3,914
  • 1
  • 19
  • 37
  • 1
    have you checked [this answer](http://stackoverflow.com/a/4252337/773623) – Jonathan Drapeau May 15 '14 at 15:38
  • @JonathanDrapeau, thx but that's not what I'm asking, in this solution the date of the formatted textfield is not given as soon as it is valid. That's why I added the CaretListener and the PropertyChangeListener, but this is not working as I expected – remi May 15 '14 at 19:11

0 Answers0