Question

I have a little Java program fully working. And I would like to make the "Enter" key working when I enter a pin Code. As I am writing this post, I can only click on the button to make it work, so I'd like to add this simple functionality without changing all the code.

This is the reason of my post, because I have found several links for it, but none of them corresponds to my situation, knowing that I already have a code working. I need to adapt what I have found there :

Allowing the "Enter" key to press the submit button, as opposed to only using MouseClick http://tips4java.wordpress.com/2008/10/10/key-bindings/ http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html http://www.javaprogrammingforums.com/java-swing-tutorials/3171-jbutton-enter-key-keyboard-action.html http://www.rgagnon.com/javadetails/java-0253.html

The fact that they're all showing solution from nohting does not help me because I can not use what they did in my own program.

Enter key

As you can see, this is the "OK" button I need to be clicked or pressed by "Enter"

Here's my code, what do you suggest to have the Enter key working?

import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.PlainDocument;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame {

    private static final long serialVersionUID = 1L;

    private JPanel container = new JPanel();
    private JPasswordField p1 = new JPasswordField(4);
    private JLabel label = new JLabel("Enter Pin: ");
    private JButton b = new JButton("OK");


    public Main() {
        this.setTitle("NEEDS");
        this.setSize(300, 500);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);

        container.setBackground(Color.white);
        container.setLayout(new BorderLayout());
        container.add(p1);
        JPanel top = new JPanel();

        PlainDocument document =(PlainDocument)p1.getDocument();

        b.addActionListener(new BoutonListener());

        top.add(label);
        top.add(p1);
        p1.setEchoChar('*');
        top.add(b);


        document.setDocumentFilter(new DocumentFilter(){

            @Override
            public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
                String string =fb.getDocument().getText(0, fb.getDocument().getLength())+text;

                if(string.length() <= 4)
                super.replace(fb, offset, length, text, attrs); //To change body of generated methods, choose Tools | Templates.
            }
        });

        this.setContentPane(top);
        this.setVisible(true);
    }

    class BoutonListener implements ActionListener {
        private final AtomicInteger nbTry = new AtomicInteger(0);
        ArrayList<Integer> pins = readPinsData(new File("bdd.txt"));

        @SuppressWarnings("deprecation")
        public void actionPerformed(ActionEvent e) {
            if (nbTry.get() > 2) {
                JOptionPane.showMessageDialog(null,
                        "Pin blocked due to 3 wrong tries");
                return;
            }
            final String passEntered=p1.getText().replaceAll("\u00A0", "");
            if (passEntered.length() != 4) {
                JOptionPane.showMessageDialog(null, "Pin must be 4 digits");
                return;
            }
            //JOptionPane.showMessageDialog(null, "Checking...");
            //System.out.println("Checking...");
            SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    boolean authenticated = false;
                    ImageIcon imgAngry = new ImageIcon("angry.png");
                    ImageIcon imgHappy = new ImageIcon("happy.png");

                    if (pins.contains(Integer.parseInt(passEntered))) {
                        JOptionPane.showMessageDialog(null, "Pin correct", "Good Pin", JOptionPane.INFORMATION_MESSAGE, imgHappy);
                        authenticated = true;
                    }

                    if (!authenticated) {
                        JOptionPane.showMessageDialog(null, "Wrong Pin", "Wrong Pin", JOptionPane.INFORMATION_MESSAGE, imgAngry);
                        nbTry.incrementAndGet();
                    }
                    return null;
                }
            };
            worker.execute();
        }

    }

    // Reading bdd.txt file
    static public ArrayList<Integer> readPinsData(File dataFile) {
        final ArrayList<Integer> data=new ArrayList<Integer>();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(dataFile));
            String line;
            try {
                while ((line = reader.readLine()) != null) {
                    try {
                        data.add(Integer.parseInt(line));
                    } catch (NumberFormatException e) {
                        e.printStackTrace();
                        System.err.printf("error parsing line '%s'\n", line);
                    }
                }
            } finally {
                reader.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("error:"+e.getMessage());
        }

        return data;
    }

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

    }
}
Was it helpful?

Solution

JTextField (which JPasswordField inherits from) provides ActionListener support for just this functionality.

p1.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        b.doClick(); // Re-use the Ok buttons ActionListener...
    }
});

Take a look at How to use text fields for more details

OTHER TIPS

JTextField yourtexfield=new JTextField(8);

yourterxtfield.addActionListener(new ActionListener(){

       public void actionPerformed(ActionEvent e){
             // your code
      }
});

I think this snipped should guide you, add this code in your class:

    @Override
public void actionPerformed(ActionEvent e) {
    b.doClick();
}

edit: oh, sorry. Didn't recognize that you are using Swing/AWT. this is a SWT functionality and therefore doesn't help with your problem.

I used the TraverseListener to implement that behavior. You could try this:

        p1.addTraverseListener(new TraverseListener() {
        @Override
        public void keyTraversed(TraverseEvent e) {
            switch (e.detail) {
              case SWT.TRAVERSE_RETURN:
                doWhateverYourButtonClickDoesHere();
                break;
            }
        }
    });

Fleshing out my comment to @Mad's answer:

[invoking button.doClick()] is not the best of solutions because it introduces an unnecessary coupling between several views Instead, use one Action and set it to both the textField and the button

The advantages:

  • (as already noted): no coupling between views
  • a single location to implement the login logic
  • has the notion of enabled, so can be disabled - and with it all views it is bound to . on a locked login

A raw (taking a bit too much responsibility, further separation strongly advised) code snippet, taking over

  • grab the valid pins
  • register the documentFilter
  • validate/lock the login

The Action:

public static class LoginAction extends AbstractAction {
    private final AtomicInteger nbTry = new AtomicInteger(0);
    private ArrayList<Integer> pins = readPinsData(new File("bdd.txt"));
    private Document doc;

    public LoginAction(String login, AbstractDocument doc) {
        super(login);
        this.doc = doc;
        doc.setDocumentFilter(new DocumentFilter(){

            @Override
            public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
                String string =fb.getDocument().getText(0, fb.getDocument().getLength())+text;
                if(string.length() <= 4)
                    super.replace(fb, offset, length, text, attrs); 
            }
        });

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (nbTry.get() > 2) {
            JOptionPane.showMessageDialog(null,
                    "Pin blocked due to 3 wrong tries");
            setEnabled(false);
            return;
        }
        String passEntered = null;
        try {
            passEntered = doc.getText(0, doc.getLength()).replaceAll("\u00A0", "");
        } catch (BadLocationException e1) {
            e1.printStackTrace();
        }
        if (passEntered.length() != 4) {
            JOptionPane.showMessageDialog(null, "Pin must be 4 digits");
            return;
        }
        boolean authenticated = false;
        ImageIcon imgAngry = new ImageIcon("angry.png");
        ImageIcon imgHappy = new ImageIcon("happy.png");

        if (pins.contains(Integer.parseInt(passEntered))) {
            JOptionPane.showMessageDialog(null, "Pin correct", "Good Pin", JOptionPane.INFORMATION_MESSAGE, imgHappy);
            authenticated = true;
        }

        if (!authenticated) {
            JOptionPane.showMessageDialog(null, "Wrong Pin", "Wrong Pin", JOptionPane.INFORMATION_MESSAGE, imgAngry);
            nbTry.incrementAndGet();
        }

    }

}

It's usage:

PlainDocument document =(PlainDocument)passwordField.getDocument();
LoginAction action = new LoginAction("OK", document);
passwordField.setAction(action);
loginButton.setAction(action);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top