0

I am currently working on an open source code for a Matrix calculator. What I am trying to achieve is to get user to enter numbers only into the JTextArea. Numbers include negative numbers and also decimal numbers. My questions are as follows:

  1. How do I restrict user inputs into the JTextArea. Inputs that the JTextArea should accept are: numbers (0-9), space, decimal point. For example, if user presses the letter 'a', the letter does not appear in the JTextArea and also he/she hears a warning sound. If the user presses a number e.g '2'it is added into the JTextArea.
  2. Or there is no solution to my first question; this on is my alternate method. How do I add an actionListener to a JTextArea. The Action Listener will be used to validate user inputs into the JTextArea. I am working with Matrices here and I would like users to input numbers only into the text area, when users press letters or other symbols, the program prompts the user that the input is invalid and that the user must enter numbers only. If there is a solution for this one, I would also like to go one step ahead to check if the numbers entered represents a valid matrix (number of columns; i.e. numbers saperated by a space; must be equal in all rows).

Snapshot of the Matrix Calculator showing letters entered into the JTextArea

I have not yet done any coding on this yet as I am not sure how to add an action listener to my JTextArea.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Heaty
  • 1
  • 2
  • 2
    Use a `DocumentFilter` on the `JTextArea`'s `Document`, have a look at [Text Component Features](https://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html) for more details. There are countless examples about how you can restrict the user input using a `DocumentFilter` on `JTextField`, but the concept is the same – MadProgrammer Sep 13 '17 at 04:53
  • 1
    As [one possible example](https://stackoverflow.com/questions/7632387/jtextarea-only-with-numbers-but-allowing-negative-values) – MadProgrammer Sep 13 '17 at 04:54
  • Thank you all very much. I have used the 'code' java.awt.event.KeyEvent 'code' and picking up every key pressed, then checking by using: 'code' String c = Character.toString(java.awt.event.KeyEvent.getKeyChar()); 'code' – Heaty Sep 27 '17 at 22:05
  • And what happens when the user pastes text into the field? You code won't work, as has already been stated, a number of times, the best solution is to use a `DocumentFilter` – MadProgrammer Sep 27 '17 at 22:22
  • Thanks @MadProgrammer. I guess I did not consider that. I will recode according to your advise. Much appreciated – Heaty Sep 27 '17 at 22:36

2 Answers2

-1

I tried to make a solution for you, it accepts only digit from 0 to 9 and space character, dot and new line character, you can add and remove other constraints as per your requirement.

jTextArea.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void removeUpdate(DocumentEvent e) {

            }

            @Override
            public void insertUpdate(DocumentEvent e) {
                // use your restriction logic here
                // allow only numeric
                Document doc = jTextArea.getDocument();
                try {
                String c = doc.getText(doc.getLength() - 1, 1);

                if(c.equals("0") || c.equals("1") || c.equals("2") || c.equals("3") || c.equals("4") || c.equals("5") || c.equals("6") || c.equals("7") || c.equals("8") || 
                        c.equals("9") || c.equals("0") || c.equals(".") || c.equals("-") || c.equals(" ") || c.equals("\n")) {

                } else {
                    String ss = doc.getText(0, doc.getLength()-1);
                    Runnable clearText = new Runnable() { 
                        public void run() { 
                            jTextArea.setText(ss); 
                        } 
                      }; 
                      SwingUtilities.invokeLater(clearText); 
                    jTextArea.setText(doc.getText(0, doc.getLength()-1));
                }
                } catch (BadLocationException e2) {
                    // TODO: handle exception
                }
            }

            @Override
            public void changedUpdate(DocumentEvent arg0) {

            }
        });

it might be not the perfect solution, but it will help you to achieve your task

Pramod Yadav
  • 245
  • 2
  • 20
  • Thank you much @PramondYadav. I have used snippet of your code along with the 'code' java.awt.event.keyEvent 'code' and that worked great for me. Much appreciated. – Heaty Sep 27 '17 at 21:59
  • A `DocumentFilter` is a better solution as it doesn't risk the chance of generating a mutation exception from the `Document`, because you've change the component while the `Document` is been mutated – MadProgrammer Sep 27 '17 at 22:23
-1

Thanks @PramodYadav for the assistance. I used snippet of your code and came up with the following using java.awt.event.KeyEvent and reading every key press using String c = character.toString(java.awt.event.KeyEvent.getKeyChar());. I am sure someone else would have a much better solution.
Refer my code below:

    JTextArea.addKeyListener(new java.awt.event.KeyAdapter() {
        public void keyTyped(java.awt.event.KeyEvent evt) {
            JTextAreaKeyTyped(evt);
        }   
    });

    private void taBKeyTyped(java.awt.event.KeyEvent evt) { 
        try{
            javax.swing.text.Document doc = taA.getDocument();
            String c = Character.toString(evt.getKeyChar());
            if (c.equals("\b") || c.equals("0") || c.equals("1") || c.equals("2") || c.equals("3") || c.equals("4") || c.equals("5") || c.equals("6") || c.equals("7") || c.equals("8") || c.equals("9") || c.equals("0") || c.equals(".") || c.equals("-") || c.equals(" ") || c.equals("\n")) {

            }
            else {
                javax.swing.JOptionPane.showMessageDialog(null, "Invalid key pressed. Please enter valid numbers, including:\n - Negative Numbers &\n - Decimal numbers");
                String ss = doc.getText(0, doc.getLength()-1);
                System.out.println(doc.getLength());
                //using lambda expression
                Runnable clearText; 
                clearText = () -> {
                    taA.setText(ss); 
                };
                javax.swing.SwingUtilities.invokeLater(clearText);
                JTextArea.setText(doc.getText(0, doc.getLength()-1));
            }
        }
        catch(HeadlessException | BadLocationException e) {
            System.out.println("Exception: " + e);
        }
    }  

Please let me know if I did ok and that I did not use a bad approach of coding.

Heaty
  • 1
  • 2
  • As, has already been stated a number of times, `KeyListener` is NOT the correct choice for filtering ANY text component, this is why the `DocumentFilter` API exists, apart from running the risk of multiple mutation issues and different platforms performing differently, this does not take into account what could happen if the user pasted text into the component or the code called `setText`, in which, both scenarios would simply bypass you listener code - again, something the `DocumentFilter` will catch – MadProgrammer Sep 27 '17 at 22:49