2

I'm trying to create a math quiz and I only want the user to be able to enter numbers whether they're negative or positive. Is there any way to do so? I've thought of using Regular Expressions but I've heard that they are bad to use. I tried using a keylistener but then what if the user pastes? I've tried parsing the string to get an integer but then the negative symbol will not work.

Any ideas?

package com.quiz.ui;

import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class SSCCE {

    private JFrame frame;

    private JPanel contentPane;

    private JTextField usernameField;

    public static void main(String[] arguments) {
        new SSCCE().construct();
    }

    public void construct() {
        frame = new JFrame("Login");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(getContentPane());
        frame.pack();
        frame.setVisible(true);
    }

    public JPanel getContentPane() {
        usernameField = new JTextField(5);
        usernameField.addKeyListener(new KeyListener() {

            @Override
            public void keyPressed(KeyEvent arg0) {
                int keyCode = arg0.getKeyCode();
                if ((keyCode > 47 && keyCode < 58) || keyCode == 45) {
                    arg0.consume();
                }
                System.out.println(arg0.getKeyCode());
            }

            @Override
            public void keyReleased(KeyEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void keyTyped(KeyEvent arg0) {
                // TODO Auto-generated method stub

            }
        });

        contentPane = new JPanel(new BorderLayout());
        contentPane.add(usernameField);

        return contentPane;
    }

}
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417

3 Answers3

12

Use DocumentFilter:

NumberOnlyFilter.java:

import javax.swing.*;
import javax.swing.text.*;
import java.util.regex.*;
public class NumberOnlyFilter extends DocumentFilter
{

    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException
    {
        StringBuilder sb = new StringBuilder();
        sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
        sb.insert(offset, text);
        if(!containsOnlyNumbers(sb.toString())) return;
        fb.insertString(offset, text, attr);
    }
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attr) throws BadLocationException
    {
        StringBuilder sb = new StringBuilder();
        sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
        sb.replace(offset, offset + length, text);
        if(!containsOnlyNumbers(sb.toString())) return;
        fb.replace(offset, length, text, attr);
    }

    /**
     * This method checks if a String contains only numbers
     */
    public boolean containsOnlyNumbers(String text)
    {
        Pattern pattern = Pattern.compile("([+-]{0,1})?[\\d]*");
        Matcher matcher = pattern.matcher(text);
        boolean isMatch = matcher.matches();
        return isMatch;
    }

}

and then you can use it like:

((AbstractDocument)yourTxtField.getDocument()).setDocumentFilter(new NumberOnlyFilter());
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
  • +1 I'm always tempted to pre-compile the pattern, but the profiled benefit is usually marginal. – trashgod Nov 05 '11 at 03:00
  • The problem with this is the symbol `-` needs to be allowed as well. –  Nov 05 '11 at 03:09
  • 1
    @Ron: Eng's suggestion is a great one (1+), and you can use Eng's suggestion and allow - easily by either parsing the String to see if it is an appropriate numeric representation, or using other logic within the filter. – Hovercraft Full Of Eels Nov 05 '11 at 03:12
  • The `adjustLabel(...)` method cannot be found. –  Nov 05 '11 at 03:14
  • @Ron Oops, I always copy this code from my old files, and forget to remove `adjustLabel()`, sorry :) – Eng.Fouad Nov 05 '11 at 03:16
  • Thanks :) Would you happen to know how to modify your Regular Expression to include the `-` symbol? I looked before asking this questions and couldn't find anything. –  Nov 05 '11 at 03:17
  • @Eng.Fouad It seems as though I can only type one character when using this filter, any ideas why? It seems to be happening because of the `containsOnlyNumbers(...)` method. –  Nov 05 '11 at 03:24
  • @Ron I am not familiar with regex so I am not sure why. Try `[\\d]` and test if you can type more than one digit. – Eng.Fouad Nov 05 '11 at 03:28
  • @Eng.Fouad I have tried `"[-+]?\\d+"` and it lets me type multiple integers but I cannot use + or - –  Nov 05 '11 at 03:32
  • @Ron um, try this one: `([+-]{0,1})?[\\d]*` – Eng.Fouad Nov 05 '11 at 03:36
4

Alternatively, consider Validating Input using an InputVerifier. A Formatted Text Field may also be suitable.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
0

You can use Integer.parseInt(String s, int radix), for decimal use 10 as a redix value.

md. ariful ahsan
  • 606
  • 7
  • 19
  • The negative symbol does not pass the test when using this method. –  Nov 05 '11 at 03:08
  • i haven't tried the code, but this link says, it will return the negative value, [link](http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Integer.html#parseInt(java.lang.String, int)) – md. ariful ahsan Nov 05 '11 at 03:30