1

I have such easy code which creates JFormattedTextField which should contain a birth date (only digits divided by hyphen):

MaskFormatter mf = new MaskFormatter("##-##-####");
mf.setPlaceholderCharacter('_');
JFormattedTextField birthDate = new JFormattedTextField(mf);

But how to create birthDate in order it would contain initial value "dd-mm-yyyy".
I know there is such thing like setPlaceholder("some string") but when i use it, only way to change walue of birthDate is to select whole existied content and then typed in new one.
My intention is to allow user to overwrite existing content sign by sign and if after lost of focus this value is not allowed, back to initial one. Eg.

1d-mm-yyyy
11-mm-yyyy
11-0m-yyyy (now birthDate is loosing focus)
dd-mm-yyyy (because value is wrong birthDate is as on the beginning)

Is such behaviour of JFormattedTextField even possible? Or maybe there is some more suitable JComponent for this?

rainbow
  • 1,161
  • 3
  • 14
  • 29
  • 1
    Or maybe there is some more suitable JComponent for this? - JSpinner – mKorbel Jun 18 '14 at 08:15
  • Or maybe there is some more suitable JComponent for this? - [JCalendar by Kai Toedter](http://toedter.com/jcalendar/) – mKorbel Jun 18 '14 at 08:16
  • quite good code, excellent formatter, have to/is required to adapt [NumberFormatter to Date](http://stackoverflow.com/a/13424140/714968) by @Robin – mKorbel Jun 18 '14 at 08:20
  • But can i do it with one JSpinner for whole date? As far as i know i will be forced to use three of them. Am i wright? – rainbow Jun 18 '14 at 08:22
  • right Editor is there again only the JFormattedTextField – mKorbel Jun 18 '14 at 08:32

1 Answers1

2

not an answer just the direction, to use some of JCalendar

simple code example for JSpinner (I'm can't found notifier for PropertyChangeListener/Support)

import java.awt.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;

public class TimeZoneSpinners {

    private final String[] zones = {"Asia/Tokyo", "Asia/Hong_Kong",
        "Asia/Calcutta", "Europe/Paris", "Europe/London",
        "America/New_York", "America/Los_Angeles"
    };
    private final JLabel[] labels = new JLabel[zones.length];
    private final SimpleDateFormat[] formats = new SimpleDateFormat[zones.length];
    private JSpinner spinner;
    private SpinnerDateModel model;
    private SimpleDateFormat format;
    private JPanel panel;
    private JFrame frame = new JFrame();

    public TimeZoneSpinners() {
        Calendar cal = Calendar.getInstance();
        Date date = cal.getTime();
        model = new SpinnerDateModel();
        model.setValue(date);
        spinner = new JSpinner(model);
        spinner.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                Date date = (Date) ((JSpinner) e.getSource()).getValue();
                for (int i = 0; i < labels.length; i++) {
                    labels[i].setText(formats[i].format(date));
                }
            }
        });
        format = ((JSpinner.DateEditor) spinner.getEditor()).getFormat();
        format.setTimeZone(TimeZone.getTimeZone(zones[0]));
        format.applyPattern("yyyy-MM-dd HH:mm:ss");
        format.applyPattern("HH:mm:ss");
        panel = new JPanel(new GridLayout(zones.length, 2, 10, 10));
        for (int i = 0; i < zones.length; i++) {
            formats[i] = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
            formats[i] = new SimpleDateFormat("HH:mm:ss");
            formats[i].setTimeZone(TimeZone.getTimeZone(zones[i]));
            JLabel label = new JLabel(zones[i]);
            labels[i] = new JLabel(formats[i].format(date));
            labels[i].setHorizontalAlignment(JLabel.RIGHT);
            panel.add(label);
            panel.add(labels[i]);
        }
        frame.setLayout(new BorderLayout(10, 10));
        frame.add(spinner, BorderLayout.NORTH);
        frame.add(panel, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TimeZoneSpinners();
            }
        });
    }
}

you should be able to override AbstractFormatter/InternationalFormatter (example for number instance only) or to override those methods for JFormattedTextField / JSpinner, and with input mast and verifier e.g.

import javax.swing.*;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.InternationalFormatter;
import java.text.DateFormat;
import java.text.Format;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class DateSpinner extends JSpinner {

    private static final long serialVersionUID = 1L;
    public DefaultFormatter _formatter;
    public DateEditor _timeEditor;
    public DateFormat _format;

    public DateSpinner() {
        this("hh:mm:ss");
    }

    public DateSpinner(String format) {
        this(format, new Date());
    }

    public DateSpinner(String format, Date date) {
        super(new SpinnerDateModel(date, null, null, Calendar.HOUR_OF_DAY));
        setFormat(format);
        customizeSpinner();
    }

    private void customizeDateEditor() {
        JFormattedTextField.AbstractFormatter formatter = _timeEditor.getTextField().getFormatter();
        if (formatter instanceof DefaultFormatter) {
            _formatter = (DefaultFormatter) formatter;
        } else {
            throw new IllegalStateException("The formatter is not an instance of DefaultFormatter.");
        }
        if (formatter instanceof InternationalFormatter) {
            Format f = ((InternationalFormatter) formatter).getFormat();
            if (f instanceof DateFormat) {
                _format = ((DateFormat) f);
            }
        }
        if (_format == null) {
            throw new IllegalStateException("The format is not an instance of SimpleDateFormat.");
        }
    }

    private void setFormat(String format) {
        _timeEditor = createDateEditor(format);
        customizeDateEditor();
        setEditor(_timeEditor);
    }

    private void customizeSpinner() {
        setLenient(false);
        setCommitsOnValidEdit(true);
        setAllowsInvalid(false);
        setOverwriteMode(true);
    }

    protected DateEditor createDateEditor(String format) {
        return new DateEditor(this, format);
    }

    public void setCommitsOnValidEdit(boolean commit) {
        _formatter.setCommitsOnValidEdit(commit);
    }

    public boolean getCommitsOnValidEdit() {
        return _formatter.getCommitsOnValidEdit();
    }

    public void setOverwriteMode(boolean overwriteMode) {
        _formatter.setOverwriteMode(overwriteMode);
    }

    public boolean getOverwriteMode() {
        return _formatter.getOverwriteMode();
    }

    public void setAllowsInvalid(boolean allowsInvalid) {
        _formatter.setAllowsInvalid(allowsInvalid);
    }

    public boolean getAllowsInvalid() {
        return _formatter.getAllowsInvalid();
    }

    public void setTimeZone(TimeZone zone) {
        _format.setTimeZone(zone);
    }

    public TimeZone getTimeZone() {
        return _format.getTimeZone();
    }

    public void setLenient(boolean lenient) {
        _format.setLenient(lenient);
    }

    public boolean isLenient() {
        return _format.isLenient();
    }
}
Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Additional question. How to get exactly what DateSpinner shows? I have in DateSpinner date '18-06-2014" but when i use getValue() i recieve Wed Jun 18 12:41:45 CEST 2014. – rainbow Jun 18 '14 at 10:52
  • I figured this out: _dateEditor.getTextField().getText() – rainbow Jun 18 '14 at 10:57
  • you have to cast somehting like as/similair `Date myDate = (Date) mySpinner/myFormattedTextField.getValue();` – mKorbel Jun 18 '14 at 11:23
  • Another small hint from my side if you have only date in format eg. 2014-06-18 you can put it straight to DateSpinner by adding oo mKorbels code such method:`public void setText(String text) { Calendar cal = Calendar.getInstance(); String[] date = text.split("-"); cal.set(Integer.parseInt(date[0]), Integer.parseInt(date[1]), Integer.parseInt(date[2])); setValue(cal.getTime()); }` – rainbow Jun 18 '14 at 12:35
  • don't to complicate simple things :-) everything is possible without to parse something – mKorbel Jun 18 '14 at 12:37
  • But then how to solve a problem if i need to fill DateSpinner with data from a file (eg. form XML)? It has to be parsed. Is there any other way? – rainbow Jun 18 '14 at 12:44
  • agree, in this case, then there isn't another way – mKorbel Jun 18 '14 at 12:57