Search code examples
javaswingjformattedtextfieldinputverifier

JFormatted Field yielding focus when it shouldn't


The other day I asked a question, here, and received a suitable answer. However, when I tried to convert the sample code into my own program and begin to morph it into my needs, it wasn't working the way it should.

I've gone through both sets of codes several times and the only real difference I see is that my code uses a panel instead of a box, however, I haven't seen any documentation describing any differences in performance with InputVerifier. My program should not allow a lenient day but it does, and allows the JFormattedField to yield focus when it shouldn't . Where is my problem?

My current Code:

public class Hello implements ActionListener{
    private JFrame frame = new JFrame();
    private JPanel panel = new JPanel();
    private Date endingDate = new Date();
    private String endingString = null;
    private SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
    private JFormattedTextField formattedField = null;
    private JLabel label1 = new JLabel();
    private JLabel label2 = new JLabel();
    private TextArea ta = new TextArea();
    private Button b = new Button("click");

    public Hello() {
        b.addActionListener(this);
        label1 = new JLabel("test");
        label2 = new JLabel("test");

        formattedField = createFormattedTextField();
        format.setLenient(false);

        panel.add(formattedField);
        panel.add(label1);
        panel.add(label2);
        panel.add(ta);
        panel.add(b);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);


    }

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

        System.out.println("Hello, World");
    }

    private JFormattedTextField createFormattedTextField() {
        JFormattedTextField formattedField = null;
        try {
            MaskFormatter dateMask = new MaskFormatter("##/##/####");
            formattedField = new JFormattedTextField(dateMask);
        } catch (ParseException ex) {
            Logger.getLogger(Hello.class.getName()).log(Level.SEVERE, null, ex);
        }
        formattedField.setColumns(10);
        formattedField.setInputVerifier(getInputVerifier());
        return formattedField;
    }

    private InputVerifier getInputVerifier() {
        InputVerifier verifier = new InputVerifier() {

            @Override
            public boolean verify(JComponent input) {
                JFormattedTextField field = (JFormattedTextField) input;
                String text = field.getText();
                return isValidDate(text);
            }

            @Override
            public boolean shouldYieldFocus(JComponent input) {
                boolean valid = verify(input);
                if (!valid) {
                    JOptionPane.showMessageDialog(null, "Please enter a valid date in format dd/mm/yyyy");
                }
                return valid;
            }

        };
        return verifier;
    }

    public boolean isValidDate(String dateString) {
        try {
            format.parse(dateString);
            return true;
        } catch (ParseException ex) {
            return false;

        }
    }

    public void actionPerformed(ActionEvent e) {
        System.out.println("Action performed");
        System.out.println(formattedField);
        endingDate = (Date) formattedField.getValue();

        System.out.println(endingDate);
        endingString = format.format(endingDate);
        System.out.println(endingString);

    }
}

Code from answer from previous question:

public class InputVerifyDate {

    private SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");

    public InputVerifyDate() {
        JFormattedTextField formattedField = createFormattedTextField();
        JTextField field = new JTextField(10);
        format.setLenient(false);

        Box box = Box.createVerticalBox();
        box.add(formattedField);
        box.add(Box.createVerticalStrut(10));
        box.add(field);
        box.setBorder(new EmptyBorder(10, 10, 10, 10));

        JFrame frame = new JFrame();
        frame.add(box);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JFormattedTextField createFormattedTextField() {
        JFormattedTextField formattedField = null;
        try {
            MaskFormatter dateMask = new MaskFormatter("##/##/####");
            formattedField = new JFormattedTextField(dateMask);
        } catch (ParseException ex) {
            Logger.getLogger(InputVerifyDate.class.getName()).log(Level.SEVERE, null, ex);
        }
        formattedField.setColumns(10);
        formattedField.setInputVerifier(getInputVerifier());
        return formattedField;
    }

    private InputVerifier getInputVerifier() {
        InputVerifier verifier = new InputVerifier() {

            @Override
            public boolean verify(JComponent input) {
                JFormattedTextField field = (JFormattedTextField) input;
                String text = field.getText();
                return isValidDate(text);
            }

            @Override
            public boolean shouldYieldFocus(JComponent input) {
                boolean valid = verify(input);
                if (!valid) {
                    JOptionPane.showMessageDialog(null, "Please enter a valid date in format mm/dd/yyyy");
                }
                return valid;
            }

        };
        return verifier;
    }

    public boolean isValidDate(String dateString) {
        try {
            format.parse(dateString);
            return true;
        } catch (ParseException ex) {
            return false;

        }
    }

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

    }
}

Solution

  • After slowly copying code from one program to the other I found the problem. You are using entirely swing components except for the TextArea, which is awt. If you change this to a swing JTextArea then the event fires as expected. :)

    I imagine this is caused by the awt layer (which I understand is a primitive foundation for swing) not understand swings' more advanced events.