Hot questions for Using JTextField in keylistener

Question:

I added event to my jTextField

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

and here is second part of my code (responsible for handling keyboard buttons):

 private void jTextField1KeyTyped(java.awt.event.KeyEvent evt) {                                     
        switch (evt.getKeyCode()) {
                case KeyEvent.VK_1:
                    print(one);
                    System.out.println("1");
                    break;
                case KeyEvent.VK_2:
                    print(two);
                    System.out.println("2");
                    break;
                case KeyEvent.VK_3:
                    print(three);
                    System.out.println("3");
                    break;
                case KeyEvent.VK_4:
                    print(four);
                    System.out.println("4");
                    break;
                case KeyEvent.VK_5:
                    print(five);
                    System.out.println("5");
                    break;
                case KeyEvent.VK_6:
                    print(six);
                    System.out.println("6");
                    break;
                case KeyEvent.VK_7:
                    print(seven);
                    System.out.println("7");
                    break;
                case KeyEvent.VK_8:
                    print(eight);
                    System.out.println("8");
                    break;
                case KeyEvent.VK_9:
                    print(nine);
                    System.out.println("9");
                    break;
                case KeyEvent.VK_0:
                    print(zero);
                    System.out.println("0");
                    break;
            }
    }                  

But it's not working. When I any button - nothing is happening.


Answer:

I strongly urge you to change your tack enterly. You should not use a KeyListener inside of a JTextField as that messes up the JTextField's functioning. Use a DocumentListener or DocumentFilter or one of the other much better options. Since you don't appear to be restricting input, go with the DocumentListener attached to the JTextField's Document via addDcoumentListener(...).

i.e,

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

    public void keyTyped(java.awt.event.KeyEvent evt) {

        void insertUpdate(DocumentEvent e) {
            // ... code to check document change here
        }

        void removeUpdate(DocumentEvent e){
            // ... code to check document change here
        }

        void changedUpdate(DocumentEvent e){
            // ... code to check document change here
        }

    }

});

Edit: if you are wanting to capture number key presses for a calculator, then don't use this either. Rather use Key Bindings.

Question:

I use Key Listener to read an imput from user but i have an issue. First of all i read to JTextField "Please enter your name". If user enters a name for example John it changes to John. But if user enters invalid character for example "7" I want to write "Please enter your name" but it writes "Please enter your name7". It is going on until give a right input. How can I correct them??

public void keyTyped(KeyEvent e) {
                int ascii = (int)e.getKeyChar();
                if((ascii >= 65 && ascii <=122) || (ascii <= 351 && ascii >= 199 )){
                    if(TextField1.getText().equals("Please enter your name"))
                        TextField1.setText("");
                }
                else
                    TextField1.setText("Please enter your name");   
            }

Answer:

Variable names should NOT start with an upper case character.

if((ascii >= 65 && ascii <=122) || (ascii <= 351 && ascii >= 199 )){

Don't use magic numbers. If you are checking for lower/upper case alphabetic characters, then use methods from the Character class like isLetter(...)

Don't use a KeyListener it is an old API. Swing has newer an better API's. For example your logic won't work if text is pasted to the text field. Use a JFormattedTextField or a DocumentFilter to check for valid data as text is typed. See the section from the Swing tutorial on How to Write a Document Filter and How to Use Text Fields for more information.

I don't recommend placing text in the text field for a prompt. For a different approach check out Text Prompt

but it writes "Please enter your name7".

The reason that happens is because the keyTyped event is generated before the Document is updated with the typed text. To execute the setText() method last you can wrap that statement in a SwingUtiltities.invokeLater(...).

I don't recommend this approach for all the reasons given above.

Question:

The following is an SSCCE code; it works OK and the KeyListener responds correctly, but adding a JTextField to the JMenuBar causes the KeyListener to not respond at all.

Go down to uncomment/comment the line that adds a JTextField to see the difference: menuBar.add(textField);

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class JMenueWithKeyListenerExample extends JPanel {

    JTextField textField;
    JMenuBar menuBar;
    JFrame f;

    public JMenueWithKeyListenerExample() {

        textField = new JTextField();

        menuBar = new JMenuBar();
        JMenu fileMenue = new JMenu("File");
        JMenuItem menuItem1 = new JMenuItem("Item 1");
        JMenuItem menuItem2 = new JMenuItem("Item 2");

        fileMenue.add(menuItem1);
        fileMenue.add(menuItem2);

        menuBar.add(fileMenue);
      //menuBar.add(textField); // switch between comment & uncomment to see the difference

        f = new JFrame();
        f.setJMenuBar(menuBar);
        f.add(this);

        f.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if ((e.getKeyCode() == KeyEvent.VK_Z) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
                    System.out.println("undo");
                }
            }
        });

        f.setSize(400, 400);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }

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

Answer:

The preferred way to add shortcut keys is to use input map and action map, like this:

f.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
        .put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK),
             "Undo");
f.getRootPane().getActionMap()
        .put("Undo", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("undo");
    }
});

Of course, in real code you should define a constant instead of hard-coding the "Undo" action name directly. And maybe define the action separately, giving it a proper name and other useful properties.

Question:

I made some searches and I didn't find how to call a function when the user press the key "space bar", I have this code:

edtCodigos.addKeyListener(new KeyAdapter() {
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_SPACE){
            callFunction();
        }
    }
)};

Note: I want to avoid the "space", the key will be used just to call the function

Any ideas how can I do it or code samples will be appreciated ;)


Answer:

"The users are used to type "space bar" to finish an operation like payment in a cashier."

Personally, I would just use an ActionListener so that the Enter key triggers the event. It just seems more natural.

import java.awt.event.*;
import javax.swing.*;

public class TestTextField {

    public static void main(String[] args) {
        final JTextField field = new JTextField(15);
        field.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                System.out.println("Enter Pressed: " + field.getText());
            }
        });
        JOptionPane.showMessageDialog(null, field);
    }
}

If you want to use Space, you can bind the key the field using Key Bindings

import java.awt.event.ActionEvent;
import javax.swing.*;

public class TestTextField {

    public static void main(String[] args) {
        final JTextField field = new JTextField(15);
        InputMap imap = field.getInputMap(JComponent.WHEN_FOCUSED);
        imap.put(KeyStroke.getKeyStroke("SPACE"), "spaceAction");
        ActionMap amap = field.getActionMap();
        amap.put("spaceAction", new AbstractAction(){
            public void actionPerformed(ActionEvent e) {
                System.out.println("Space Pressed: " + field.getText());
            }
        });
        JOptionPane.showMessageDialog(null, field);
    }
}

You could even go as far as using a DocumentListener to listen for changes in the underlying document of the text field, and check the last character entered was a space (but this seems like a bit much - Just some info for you to learn the workings for text components :-)

Pick your flavor. I like the first.

Question:

Is it a good practice to add few listeners for JComponent in different part of code? Should I create one bigger listener?

For example I have JTextField, I noticed that both KeyListeners are called.

 JTextField textField = new JTextField();
  textField.addKeyListener(new KeyListener()
  {
     @Override
     public void keyTyped(KeyEvent e)
     {

     }

     @Override
     public void keyPressed(KeyEvent e)
     {

     }

     @Override
     public void keyReleased(KeyEvent e)
     {
        something();
     }
  });

  textField.addKeyListener(new KeyListener()
  {
     @Override
     public void keyTyped(KeyEvent e)
     {

     }

     @Override
     public void keyPressed(KeyEvent e)
     {

     }

     @Override
     public void keyReleased(KeyEvent e)
     {
        somethingElse();
     }
  });

Answer:

Well, it's bad practice to use KeyListener (generally, but especially) with text components.

  • Is it good practice to use multiple listeners on the same component, generally yes.
  • Is it good practice to use single use listeners with components, yes.
  • Is it good practice to have one big listener, IMHO, no. The reasoning is, you want to create small units of work that do a single, isolated job. Sure you might be able to abstract a listener which would allow you to re-use, but having a single monolithic listener is just a maintenance nightmare

Most listener interfaces tend to have "adapter" class, which are just concrete implementations of the listener interface without any functionality, so you can pick and choose the methods you actually want to use

Question:

This is a code sample from a feet<->meters converter. My problem: It doesn't update the current input, for example: If the text in the JTextField is "50", the textField.getText()only gives the String "5", so the double result would be 5.0. As a consequence, a "5" in the JTextField gives an error in double result = Double.parseDouble(textField.getText()); "Empty String". Thanks in advance for your answers!

public static void addKL(JTextField textField, JTextField textField2, String name) {

    textField.addKeyListener(new KeyAdapter() {
        public void keyPressed(KeyEvent evt) {
            if(evt.getKeyCode() == KeyEvent.VK_1||evt.getKeyCode() == KeyEvent.VK_2||evt.getKeyCode() == KeyEvent.VK_3||evt.getKeyCode() == KeyEvent.VK_4||evt.getKeyCode() == KeyEvent.VK_5||evt.getKeyCode() == KeyEvent.VK_6||evt.getKeyCode() == KeyEvent.VK_7||evt.getKeyCode() == KeyEvent.VK_9||evt.getKeyCode() == KeyEvent.VK_COLON||evt.getKeyCode() == KeyEvent.VK_BACK_SPACE                           ) {
                double result = Double.parseDouble(textField.getText());
                if(name=="ftFIELD") {
                    textField2.setText("" + result/3.2808);
                }
                else if(name=="mFIELD") {
                    textField2.setText("" + result*3.2808);
                }
            }
        }
    });
}

Note: Ofcourse an else is missing if the KeyEvent isnt valid, but I didn't want to continue coding before this error isn't fixed.


Answer:

You are using the wrong event, try keyReleased instead. Also fixed the string comparison

    text.addKeyListener(new KeyAdapter() {
        public void keyReleased(KeyEvent evt) {
            if(evt.getKeyCode() == KeyEvent.VK_1||evt.getKeyCode() == KeyEvent.VK_2||evt.getKeyCode() == KeyEvent.VK_3||evt.getKeyCode() == KeyEvent.VK_4||evt.getKeyCode() == KeyEvent.VK_5||evt.getKeyCode() == KeyEvent.VK_6||evt.getKeyCode() == KeyEvent.VK_7||evt.getKeyCode() == KeyEvent.VK_9||evt.getKeyCode() == KeyEvent.VK_COLON||evt.getKeyCode() == KeyEvent.VK_BACK_SPACE                           ) {
                double result = Double.parseDouble(text.getText());

                if("ftFIELD".equals(name)) {
                    textField2.setText("" + result/3.2808);
                }
                else if("mFIELD".equals(name)) {
                    textField2.setText("" + result*3.2808);
                }
            }
        }
    });

Question:

I search for an answer to my problem but nothing helps. Here is my code:

jtf = new JTextField(15);
jtf.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() 
{
    public void keyPressed(KeyEvent evt)
    {
        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
        {
            jb.doClick();
        }
    }
});

How can I trigger JButton when pressing enter in a JTextField or panel or whatever else?

edit: solved!

private class ListenForButton implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();
        if (source == jb2) {
            System.exit(0);
        } else if (source == jb) {
            ..
        } else { 
          ..
        }
        }
        catch (SQLException | HeadlessException a) {
            ..
        }
        } else if (source == jtf) // its work now
        {
            jb.doClick();
        }
    }

Answer:

Can you give us more context?

I tried adding a enter listener on the text field and it seems to be working just fine, here is my code.

package com.apixandru.jvshot;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import static java.awt.BorderLayout.EAST;
import static javax.swing.JOptionPane.showMessageDialog;

/**
 * @author Alexandru-Constantin Bledea
 * @since Sep 12, 2016
 */
public class Test {

    public static void main(String[] args) {

        JButton jb = new JButton("Search");
        jb.addActionListener((evt) -> showMessageDialog(null, "Button 'clicked'"));

        JTextField jtf = new JTextField(15);
        jtf.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent evt) {
                if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
                    jb.doClick();
                }
            }
        });

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(jtf);
        panel.add(jb, EAST);
        panel.setBorder(new EmptyBorder(5, 5, 5, 5));

        JFrame frame = new JFrame();
        frame.setContentPane(panel);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);

    }

}

Question:

I have looked over this code and i don't know what is wrong. I keep getting incorrect outputs when i enter a command (any input). Please look at the bottom part of my code.

public class gui {

    private final static javax.swing.JFrame frame = new javax.swing.JFrame();
    private final static javax.swing.JPanel panel = new javax.swing.JPanel();
    public final static javax.swing.JTextArea outtextArea = new javax.swing.JTextArea("");
    public final static javax.swing.JTextField intextArea = new javax.swing.JTextField();

    public static void main(String[] args) {

        java.awt.Font font = new java.awt.Font(java.awt.Font.SANS_SERIF, java.awt.Font.PLAIN, 15);
        String command;

        /* Optional */
        frame.setTitle("Console");
        frame.setUndecorated(true);
        frame.getRootPane().setWindowDecorationStyle(javax.swing.JRootPane.FRAME); // COMMENT THIS OUT WHEN COMPLETE
        frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); //if exit command, dispose() first
        frame.setBackground(java.awt.Color.BLACK);

        /* size */
        frame.setMinimumSize(new java.awt.Dimension(0b001011010100,0b000110000100));
        frame.setLocation(0,0);
        frame.setExtendedState(javax.swing.JFrame.MAXIMIZED_BOTH);

        /* Sets panel */
        panel.setBackground(java.awt.Color.PINK); // if sees pink, has error
        panel.setLayout(new java.awt.BorderLayout());
        panel.setSize(frame.getWidth(),frame.getHeight());

        /* Sets text area */
        //javax.swing.JScrollPane inscrollPane = new javax.swing.JScrollPane(intextArea);
        intextArea.setHorizontalAlignment(javax.swing.JTextField.LEFT);
        intextArea.setFont(font);
        intextArea.setBackground(java.awt.Color.BLACK);
        intextArea.setForeground(java.awt.Color.GREEN);
        intextArea.setFocusable(true);

        javax.swing.JScrollPane outscrollPane = new javax.swing.JScrollPane(outtextArea);
        outtextArea.setRows(10);
        outtextArea.setLineWrap(true);
        outtextArea.setFont(font);
        outtextArea.setBackground(java.awt.Color.BLUE);
        outtextArea.setForeground(java.awt.Color.GREEN);
        outtextArea.setEditable(false);

        /* Sets all necessary components */
        frame.add(panel);
        panel.add(outscrollPane,java.awt.BorderLayout.CENTER);
       // panel.add(inscrollPane,java.awt.BorderLayout.SOUTH);
        panel.add(intextArea,java.awt.BorderLayout.SOUTH);

        /* Adjusts components */
        frame.pack();
        frame.setVisible(true);

        //every time a command is entered, it is sent to handler and 
        //textbox should be cleared

// THIS BELOW IS WHERE THE PROBLEM LIES/////////////////////////////
        boolean keepGoing=true;
        while(keepGoing){
            command = intextArea.getText();
            String refactored;
            if(entering_a_command(command) && !command.equals("exit")){
                refactored=command.substring(0,command.length()-1);
                outtextArea.append(refactored+"\n");
                intextArea.setText("");
            }
            else if(!command.equals("exit")){//no need to read before submission
                outtextArea.append("");
                command=intextArea.getText();
            }
            else{
                outtextArea.append("EXITING\n");
                keepGoing=false;
            }
        }

    }
    /*
        Method is strictly for entering user input at appropriate time
    */
    private static boolean entering_a_command(String temp){
        //handler.print(temp);
        return temp.contains("="); //key to submit user input
    }
}

My input:

  • 12345=
  • 123456=
  • This is hell=
  • This is hello=

My EXPECTED output:

  • 12345
  • 123456
  • This is hell
  • This is hello

My ACTUAL output:

  • 12345
  • 12345
  • This is hell
  • This is hell

My problem: When i enter an input the first time, it all checks out. When i enter an input the second time, an input that has greater length than the first, it is automatically submitted just as if i had pressed the trigger key (=).

The input box is the black box in the bottom. To submit an input, press '='


Answer:

The problem is that you're abusing the threading model. You shouldn't be accessing UI components in a thread other than the UI thread - and having a tight loop like this is pretty much always a bad idea. You should read about the Swing threading model. From that tutorial:

Swing event handling code runs on a special thread known as the event dispatch thread. Most code that invokes Swing methods also runs on this thread. This is necessary because most Swing object methods are not "thread safe": invoking them from multiple threads risks thread interference or memory consistency errors.

Instead, you should add an event listener to your text area. There are loads of options here, none of which is obviously ideal, unfortunately. Adding a key listener and handling keyTyped sounds good - but you get the event before the key ends up in the text area, which isn't ideal. Adding a document listener is a nice abstraction in that then it doesn't matter how the text is changed (e.g. programmatically) - but you can't mutate the document within a listener, so you can't clear it.

As a starting point, adding a key listener and handling keyReleased works well at least for the simple case. Get rid of your current loop (and the unconventionally named entering_a_command method) and replace them with:

intextArea.addKeyListener(new java.awt.event.KeyAdapter() {
    @Override public void keyReleased(java.awt.event.KeyEvent e) {
        String command = intextArea.getText();
        if (!command.contains("=")) {
            return;
        }

        command = command.substring(0, command.length() - 1);
        if (command.equals("exit")) {
            frame.setVisible(false);
            frame.dispose();
            return;
        }
        outtextArea.append(command + "\n");
        intextArea.setText("");
    }
});