0

I have a 'formatted' field - that is that it must be finally in a form like this: xx/xxxx/xx I'd like to make it so that while typing you get the '/' added automatically.

The way that I am trying to cobble together is something like this:

JTextField field = new JTextField ("xx/xxxx/xx");

// a focus listener to clear the "xx/xxxx/xx" on focus & restore on focus-out
// the override the 'document' with this:
field.setDocument (new PlainDocument () {
    public void insertString (int off, String str, AttributeSet attr) throws BadLocationException {
      if (off == 2 || off == 7) {
        super.insertString (off + 1, str + "/", attr);
      }
    }
}

This seems like it is going to break - and how do I properly deal with when it goes from: xx/xx.. to xx? I think having them delete the '/' is ok.

I feel there should be a better way? Maybe a library I could use? Something other than my...special stuff.

Thanks for any input you have!!

kleopatra
  • 51,061
  • 28
  • 99
  • 211
rybit
  • 716
  • 3
  • 17
  • 25

2 Answers2

3

Hmm you could use a JFormattedTextField have a look at the example below, this will create a JFormattedTextField whic will accept only numbers and put them in the form XX/XXXX/XX:

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.text.ParseException;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.text.MaskFormatter;

public class FormattedTextFieldExample extends JFrame {

    public FormattedTextFieldExample() {
        initComponents();
    }

    private void initComponents() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(new Dimension(200, 200));
        getContentPane().setLayout(new FlowLayout(FlowLayout.LEFT));

        MaskFormatter mask = null;
        try {
            //
            // Create a MaskFormatter for accepting phone number, the # symbol accept
            // only a number. We can also set the empty value with a place holder
            // character.
            //
            mask = new MaskFormatter("##/####/##");
            mask.setPlaceholderCharacter('_');
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //
        // Create a formatted text field that accept a valid phone number.
        //
        JFormattedTextField phoneField = new JFormattedTextField(mask);
        phoneField.setPreferredSize(new Dimension(100, 20));
        getContentPane().add(phoneField);
    }

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

            public void run() {
                new FormattedTextFieldExample().setVisible(true);
            }
        });
    }
}

Reference:

David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • Wont that only do it once the user exits the field? I was trying to do it while they type (I was looking @ http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html) – rybit Aug 06 '12 at 06:43
  • @thelonesquirrely Uhm have you even tried it? No it wont. The masks are already inserted when using `JFormattedTextField` – David Kroukamp Aug 06 '12 at 06:58
  • Sorry! I wasn't in front of my dev machine when I read this, it works brilliantly – rybit Aug 06 '12 at 07:16
  • I was looking for something that looked a little more 'webby' in the sense that it doesn't have the '/' there permanently. more of a stylistic thing instead of a functionality thing. Though I miss out on some of the features of the formatted text editor. – rybit Aug 06 '12 at 07:45
  • 1
    don't use setXXSize _ever_ (see http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi/7229519#7229519) Nevertheless, +1 for formattedTextField and maskFormatter :-) – kleopatra Aug 06 '12 at 08:21
0

To achieve this I did this:

JTextField field = new JTextField ();

field.setDocument (new PlainDocument () {
  public void insertString (int off, String str, AttributeSet attr) throws BadLocationException {
    if (off < 10) {  // max size clause
      if (off == 1 || off == 6) { // insert the '/' occasionally
        str = str + "/";
      }
      super.insertString (off, str, attr);
    }
  }
});

field.setText ("xx/xxxx/xx"); // set AFTER otherwise default won't show up!
field.setForeground (ColorConstants.DARK_GRAY_080); // make it light! 
field.addFocusListener (new ClearingFocusListener (field)); // could be done in an anonymous inner class - but I use it other places

private static class ClearingFocusListener implements FocusListener {
  final private String initialText;
  final private JTextField field;

  public ClearingFocusListener (final JTextField field) {
    this.initialText = field.getText ();
    this.field = field;
  }

  @Override
  public void focusGained (FocusEvent e) {
    if (initialText.equals (field.getText ())) {
      field.setText ("");
      field.setForeground (ColorConstants.DARK_GRAY_080);
    }
  }

  @Override
  public void focusLost (FocusEvent e) {
    if ("".equals (field.getText ())) {
      field.setText (initialText);
      field.setForeground (ColorConstants.LIGHT_GRAY_220);
    }
  }
}

This is different that the other solution in that the '/' doesn't exist when there is no text, it is added at the right places. It doesn't currently doesn't deal with any of the replacement stuff -- eh. :/

Seki
  • 11,135
  • 7
  • 46
  • 70
rybit
  • 716
  • 3
  • 17
  • 25