Frage

I have a problem when I am trying to get the size of a JFormattedTextField. Actually I need the user to enter a simple pinCode, and then get the size of what he enters to loop on it right after it. If he entered 4 digits it's ok, or else he has to do it again. But when I run my project, I have an infinite loop with "Pin must be 4 digits"...

I already found this link, but it did not fix my problem.

Here's my code :

package codePin;

import java.io.*;
import java.text.NumberFormat;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame {

    private static final long serialVersionUID = 1L;

    private JPanel container = new JPanel();
    private JFormattedTextField jtf = new JFormattedTextField(NumberFormat.getIntegerInstance());
    private JLabel label = new JLabel("Enter Pin: ");
    private JButton b = new JButton("OK");

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

        container.setBackground(Color.white);
        container.setLayout(new BorderLayout());
        JPanel top = new JPanel();
        Font police = new Font("Arial", Font.BOLD, 14);
        jtf.setFont(police);
        jtf.setPreferredSize(new Dimension(150, 30));
        jtf.setForeground(Color.BLUE);

        b.addActionListener(new BoutonListener());

        top.add(label);
        top.add(jtf);
        top.add(b); 

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

    class BoutonListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            int nbTry = 0;
            boolean authenticated = false;

            do {
                do {

                    if (jtf.getText().length() != 4) { 
                        System.out.println("Pin must be 4 digits");
                    } else {
                        System.out.println("Checking...");
                    }

                    ArrayList<Integer> pins = new ArrayList<Integer>(); 
                    readPinsData(new File("bdd.txt"), pins);

                    String[] thePins = new String[pins.size()];
                    for (int i = 0; i < thePins.length; i++) {
                        thePins[i] = pins.get(i).toString();
                    }

                    String passEntered = String.valueOf(jtf);

                    for (int i = 0; i < thePins.length; i++) {
                        if (passEntered.equals(thePins[i]) && jtf.getText().length() == 4) {
                            System.out.println(":)");
                            authenticated = true;
                            break;
                        }
                    }
                } while (jtf.getText().length() != 4);
                if (!authenticated && jtf.getText().length() == 4) {
                    System.out.println(":(");
                    nbTry++;
                }
            } while (nbTry < 3 && !authenticated);
            //System.out.println("TEXT : jtf " + jtf.getText());

        }
    }

    // Function to read/access my pins database (file bdd.txt)
    static public boolean readPinsData(File dataFile, ArrayList<Integer> data) {
        boolean err = false;
        try {
            Scanner scanner = new Scanner(dataFile);
            String line;
            while (scanner.hasNext()) {
                line = scanner.nextLine();
                try {
                    data.add(Integer.parseInt(line));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                    err = true;
                }
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            err = true;
        }

        return err;
    }

    public static void main(String[] args) {

        Main fen = new Main();
    }
}

bdd.txt :

1111
1234
2222
3333
4444
5555
6666
7777
8888
9999

How can I do that ? Any ideas ?

Thanks, Florent.

War es hilfreich?

Lösung

None of the answers actually work. Short answer, you have to do the following check:

if (jtf.getText().replaceAll("\u00A0","").length() != 4) {
    System.out.println("Pin must be 4 digits");
    JOptionPane.showMessageDialog(null,"Pin must be 4 digits");
    return;
}

Explanation: the unicode character \u0160 which is used in the NumberFormat is not a non-breaking space. After the \u there must be the hexadecimal representation of the character, that is \u00A0.

Complete code:

package codePin;
import java.io.*;
import java.text.NumberFormat;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.atomic.AtomicInteger;


public class Main extends JFrame {

    private static final long serialVersionUID = 1L;

    private JPanel container = new JPanel();
    private JFormattedTextField jtf = new JFormattedTextField(NumberFormat.getIntegerInstance());
    private JLabel label = new JLabel("Enter Pin: ");
    private JButton b = new JButton("OK");

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

        container.setBackground(Color.white);
        container.setLayout(new BorderLayout());
        JPanel top = new JPanel();
        Font police = new Font("Arial", Font.BOLD, 14);
        jtf.setFont(police);
        jtf.setPreferredSize(new Dimension(150, 30));
        jtf.setForeground(Color.BLUE);

        b.addActionListener(new BoutonListener());

        top.add(label);
        top.add(jtf);
        top.add(b);

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

    class BoutonListener implements ActionListener {
        private final AtomicInteger nbTry = new AtomicInteger(0);
        ArrayList<Integer> pins = readPinsData("bdd.txt");
        public void actionPerformed(ActionEvent e) {
            if (nbTry.get() > 2) {
                JOptionPane.showMessageDialog(null, "Number of tries exceeded");
                return;
            }
            final String passEntered=jtf.getText().replaceAll("\u00A0", "");
            if (passEntered.length() != 4) {
                System.out.println("Pin must be 4 digits");
                JOptionPane.showMessageDialog(null, "Ping must be 4 digits");
                return;
            }
            System.out.println("Checking...");
            SwingWorker worker = new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    boolean authenticated = false;
                    if (pins.contains(Integer.parseInt(passEntered))) {
                        System.out.println(":)");
                        authenticated = true;
                    }

                    if (!authenticated) {
                        System.out.println(":(");
                        nbTry.incrementAndGet();
                    }
                    return null;
                }
            };
            worker.execute();
        }


    }

    // Function to read/access my pins database (file bdd.txt)
    static public ArrayList<Integer> readPinsData(String dataFile) {
        final ArrayList<Integer> data=new ArrayList<Integer>();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(new File(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() {
                Main fen = new Main();
            }
        });

    }
}

Andere Tipps

You seem to have misunderstood the concept of an actionListener: The Listener listens to your answer, and does nothing else. You have loops in the listener that wait for an correct amount of digits - thats wrong, you need to only handle one input in the listener (and after another click, the listener will be called again). And so, for sure, because you got your loop with only one answer the user entered, you got a non-ending loop. Just handle one input in the action listener, and you'll be fine. Here is an description how to write it: http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html.

You have an infinite loop in your code, so when the BoutonListener.actionPerformed is called for the first time it just spins there without exiting.

You will have to significantly modify your code. Start with extracting the variables used in the do-while conditions into the fields, and update these fields each time the actionPerformed is called.

You're running into an endless loop, because the user has no chance to reenter his PIN, if it doesn't match the length.

Looping and Listeners don't work quite well in this way. Why don't you just keep the relevant variables (e.g. nbTry) as members and perform your checks without looping?

Your mistake is in this if() condition :

for (int i = 0; i < thePins.length; i++) {
    if (passEntered.equals(thePins[i]) && jtf.getText().length() == 4) {
        System.out.println(":)");
        authenticated = true;
        break;
    }
}

As the legnth of your pinCode is not equal to 4, you never validate the condition, and never break the do-while() loop.

By the way, using break is not a very good idea since you can always find a loop type or condition that allows you to avoid it !

You can get the length of the text of a JFormattedTextField, say jtf here this way:

jtf.getText().length(); 

Note: according to what you want use this :

String s = jtf.getText();
s = s.replaceAll(",", "");
if (s.length() != 4) 

But the problem you've got is due to the way you've used the loops.

I think you want to show a reaction when the user enters exactly for digits, and if so, you don't need a loop at all.


According to the comments:

  • Remove the loops (nTry < 3 ... )
  • Define int nbTry = 0; as a class member and keep track of it in your action listener.
  • Inside the BoutonListener check if everything is right do whatever otherwise nTry++, and if nTry >=3 do whatever you want.

import java.io.*;
import java.text.NumberFormat;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame {
    //-------------------------------here
    int nbTry = 0;
    //-------------------------------here

    private static final long serialVersionUID = 1L;

    private JPanel container = new JPanel();
    private JFormattedTextField jtf = new JFormattedTextField(NumberFormat.getIntegerInstance());
    private JLabel label = new JLabel("Enter Pin: ");
    private JButton b = new JButton("OK");

    public Main() {


        jtf.getText().length();
        this.setTitle("APP");
        this.setSize(300, 500);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);

        container.setBackground(Color.white);
        container.setLayout(new BorderLayout());
        JPanel top = new JPanel();
        Font police = new Font("Arial", Font.BOLD, 14);
        jtf.setFont(police);
        jtf.setPreferredSize(new Dimension(150, 30));
        jtf.setForeground(Color.BLUE);

        b.addActionListener(new BoutonListener());

        top.add(label);
        top.add(jtf);
        top.add(b); 

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

    class BoutonListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            String s = jtf.getText();
            s = s.replaceAll(",", "");
            System.out.println(s);
            System.out.println(s.length());
            boolean authenticated = false;
            if (nbTry > 3) {
                //Oops, enough!
            }
            if (s.length() != 4) { 
                System.out.println("Pin must be 4 digits");
            } else {
                System.out.println("Checking...");
                //and check here!
                ArrayList<Integer> pins = new ArrayList<Integer>(); 
                readPinsData(new File("bdd.txt"), pins);

                String[] thePins = new String[pins.size()];
                for (int i = 0; i < thePins.length; i++) {
                    thePins[i] = pins.get(i).toString();
                }

                String passEntered = String.valueOf(jtf);

                for (int i = 0; i < thePins.length; i++) {
                    if (passEntered.equals(thePins[i]) && jtf.getText().length() == 4) {
                        System.out.println(":)");
                        authenticated = true;
                        break;
                    }
                }
                if (authenticated) {
                    //Congratulation! 
                }
                else {
                    nbTry++;
                }
            }
        }
    }

    // Function to read/access my pins database (file bdd.txt)
    static public boolean readPinsData(File dataFile, ArrayList<Integer> data) {
        boolean err = false;
        try {
            Scanner scanner = new Scanner(dataFile);
            String line;
            while (scanner.hasNext()) {
                line = scanner.nextLine();
                try {
                    data.add(Integer.parseInt(line));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                    err = true;
                }
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            err = true;
        }

        return err;
    }

    public static void main(String[] args) {

        Main fen = new Main();
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top