javaregexswingjavax.swing.text

Restrict Input of JTextField to Double Numbers?


In java , i am trying to make simple currency converter, but for that i need a text field which can restrict input to numbers only and more importantly double numbers. I tried using JFormatedTextField but it only format the input after you have done your input and click elsewhere but i need to restrict TextField to consume() each invalid character while doing input.

Possible Attempts:

Using JFormatedTextField:

JFormatedTextField textField = new JFormatedTextField(new DoubleFormat());
textField.setBounds(190, 49, 146, 33);
frame.getContentPane().add(textField);
textField.setColumns(10);

Using KeyTyped Event:

char c = arg0.getKeyChar();
if(!(Character.isDigit(c) || c == KeyEvent.VK_BACK_SPACE || c== KeyEvent.VK_DELETE)){
    arg0.consume();
}

Using KeyTyped Event with regex:

if(!((textField.getText().toString+arg0.getKeyChar()).matches("[0-9]*(.[0-9]*)?"))){
   arg0.consume();
}

Second and third attempt were close but then second attempt failed on point values and third attempt always read first character on textField no matter what it is, So any suggestions ? i am not very fond of JAVA GUI so kindly be patient.


Solution

  • If you know how many places before and after decimal point you want, you can also use MaskFormatter. For example:

    JFormattedTextField field = new JFormattedTextField(getMaskFormatter("######.##"));
    
    (...)
    
    private MaskFormatter getMaskFormatter(String format) {
        MaskFormatter mask = null;
        try {
            mask = new MaskFormatter(format);
            mask.setPlaceholderCharacter('0');
        }catch (ParseException ex) {
            ex.printStackTrace();
        }
        return mask;
    }
    

    However it will chenge a look of JTextField, so it will be always visible 000000.00 in it.

    EDIT

    Another way, not too elegant, but in my opinion working. Try with DecumentListener, maybe it will suit your needs:

    field = new JFormattedTextField();
    field.getDocument().addDocumentListener(new DocumentListener() {
        @Override
        public void insertUpdate(DocumentEvent e) {
            Runnable format = new Runnable() {
                @Override
                public void run() {
                    String text = field.getText();
                    if(!text.matches("\\d*(\\.\\d{0,2})?")){
                        field.setText(text.substring(0,text.length()-1));
                    }
                }
            };
            SwingUtilities.invokeLater(format);
        }
    
        @Override
        public void removeUpdate(DocumentEvent e) {
    
        }
    
        @Override
        public void changedUpdate(DocumentEvent e) {
    
        }
    });
    

    I used regex: \\d*(\\.\\d{0,2})? because two decimal places is enough for currency.