Search code examples
javaswingjlabeljtextfieldinputverifier

InputVerifier don't display each component icon(lable)


I have a form that set a input verifier to it.

I want when a user type a correct value for a text field and want to go to other text field, a check icon should be display besides of text field. But now in my code, when user type a correct value on first text field an go to other, Two icons displayed together!

public class UserDialog extends JDialog {

JButton cancelBtn, okBtn;
JTextField fNameTf, lNameTf;
JRadioButton maleRb, femaleRb;
ButtonGroup group;
JLabel fNameLbl, fNamePicLbl, lNameLbl, lNamePicLbl, genderLbl, tempBtn, temp3;

    public UserDialog() {
    add(createForm(), BorderLayout.CENTER);
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    setLocation(400, 100);
    pack();
    setVisible(true);
}
    public JPanel createForm() {
    JPanel panel = new JPanel();
    ImageIcon image = new ImageIcon("Check.png");

    okBtn = new JButton("Ok");
    cancelBtn = new JButton("Cancel");
    tempBtn = new JLabel();
    fNameLbl = new JLabel("First Name");
    fNamePicLbl = new JLabel(image);
    fNamePicLbl.setVisible(false);
    lNameLbl = new JLabel("Last Name");
    lNamePicLbl = new JLabel(image);
    lNamePicLbl.setVisible(false);
    genderLbl = new JLabel("Gender");

    maleRb = new JRadioButton("Male");
    femaleRb = new JRadioButton("Female");
    temp3 = new JLabel();
    group = new ButtonGroup();
    group.add(maleRb);
    group.add(femaleRb);

    fNameTf = new JTextField(10);
    fNameTf.setName("FnTF");
    fNameTf.setInputVerifier(new MyVerifier(new JComponent[]{maleRb, femaleRb, okBtn}));
    lNameTf = new JTextField(10);
    lNameTf.setName("LnTF");
    lNameTf.setInputVerifier(new MyVerifier(new JComponent[]{maleRb, femaleRb, okBtn}));

    panel.add(fNameLbl);
    panel.add(fNameTf);
    panel.add(fNamePicLbl);
    panel.add(lNameLbl);
    panel.add(lNameTf);
    panel.add(lNamePicLbl);
    panel.add(genderLbl);
    JPanel radioPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
    radioPanel.add(maleRb);
    radioPanel.add(femaleRb);
    panel.add(radioPanel);
    panel.add(temp3);
    panel.add(okBtn);
    panel.add(cancelBtn);
    panel.add(tempBtn);

    panel.setLayout(new SpringLayout());
    SpringUtilities.makeCompactGrid(panel, 4, 3, 50, 10, 80, 60);
    return panel;
}
    public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new UserDialog();
        }
    });
}

public class MyVerifier extends InputVerifier {
    private JComponent[] component;

    public MyVerifier(JComponent[] components) {
        component = components;
    }

    @Override
    public boolean verify(JComponent input) {
        String name = input.getName();

        if (name.equals("FnTF")) {
            String text = ((JTextField) input).getText().trim();
            if (text.matches(".*\\d.*") || text.length() == 0) {
                //disable dependent components
                for (JComponent r : component) {
                    r.setEnabled(false);
                }
                return false;
            }
        } else if (name.equals("LnTF")) {
            String text = ((JTextField) input).getText();
            if (text.matches(".*\\d.*") || text.length() == 0) {
                //disable dependent components
                for (JComponent r : component) {
                    r.setEnabled(false);
                }
                return false;
            }
        }
        //enable dependent components
        for (JComponent r : component) {
            r.setEnabled(true);
        }
        fNamePicLbl.setVisible(true);
        lNamePicLbl.setVisible(true);
        return true;
    }
}
}
}

Updated

 public class MyVerifier extends InputVerifier {
    private JComponent[] component;

    public MyVerifier(JComponent[] components) {
        component = components;
    }

    @Override
    public boolean verify(JComponent input) {
        String name = input.getName();

        if (name.equals("FnTF")) {
            String text = ((JTextField) input).getText().trim();
            if (text.matches(".*\\d.*") || text.length() == 0) {
                return false;
            }
        } else if (name.equals("LnTF")) {
            String text = ((JTextField) input).getText();
            if (text.matches(".*\\d.*") || text.length() == 0) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean shouldYieldFocus(JComponent input) {
        boolean isValidDate = verify(input);
        if (isValidDate) {
            for (JComponent r : component) {
                r.setEnabled(true);
            }
        } else {
            for (JComponent r : component) {
                r.setEnabled(false);
            }
        }
        return isValidDate;
    }

Solution

  • But now in my code, when user type a correct value on first text field an go to other, Two icons displayed together!

    Because you did so: (Read the comments)

    public boolean verify(JComponent input) {
            String name = input.getName();
    
            if (name.equals("FnTF")) {
                // your code
                }
            } else if (name.equals("LnTF")) {
                // your code
    
            }
            //enable dependent components
            for (JComponent r : component) {
                r.setEnabled(true);
            }
            /* And Now we are here */
            fNamePicLbl.setVisible(true); 
            lNamePicLbl.setVisible(true);
             // making visible two of them at once as soon as verify is called 
                // on any one of the components, verifier is registered
    
            return true;
        }
    

    setVisible should be controlled by the if-else condition too. For your better understanding you need to do something like this:

          if (text.matches(".*\\d.*") || text.length() == 0) {
               // your code
            }
            else
            {
                fNamePicLbl.setVisible(true);
    
            } 
    

    Second Issue:

        fNameTf.setInputVerifier(new MyVerifier(new JComponent[]{maleRb, femaleRb, okBtn}));
        lNameTf = new JTextField(10);
        lNameTf.setName("LnTF");
        lNameTf.setInputVerifier(new MyVerifier(new JComponent[]{maleRb, femaleRb, okBtn}));
    

    The MyVerfier has the common code to verify both input field. But you are creating two instances of it with same instances of components. Create one and set it as the input verifier of the two field.

    You might want to create two different InputVerifier class for the two Text Field. FnTFVerifier and LnTFVerifier. Then put your verification code that relates them e.g., enabling the radio buttons and showing the label with check.png. most of the if-else checking will go-away.

    But I think, this should not really be the preferable way. As the two text field has the common functionality, one InputVerifier class and instance is sufficient. you would have to just encapsulate the input text field and related cehckLabel to one component, then register the InputVerifier instances to this component.

    Third issue: you are misusing verify function:

    The verify function is meant to be used for nothing but verify data: whether data is valid or not with user required condition. It should do nothing more. InputVerifier has another function boolean ShouldYieldFocus(Jcomponent): Before focus is transfered to another Swing component that requests it, the input verifier's shouldYieldFocus method is called, which decides whither the component under verification should lose focus or not. Focus is transferred only if this method returns true. You should however write the required state change of components inside this function.

    public boolean shouldYieldFocus(JComponent input) {
        boolean isDataValid =  verify(input);
    
        if(isDataValid); //do stuff
    
        return isDataValid; // if verify is true(valid) return true;
     }