-1

I have a delicate problem!

I have a form that set input verifier to text fields, and when user type a incorrect value, other text fields and radio buttons should be disable.

In second text filed (last name), When user type a incorrect value, other components disable perfectly, But when user edit that value to correct it, (for e.x by removing digit), user should user keyboard tab button to enable other components (radio buttons) and I want to enable with clicking to radio buttons too.

Here is my code:

public class UserDialog3 extends JDialog implements ActionListener {
JButton cancelBtn, okBtn;
JTextField fNameTf, lNameTf;
JRadioButton maleRb, femaleRb;
ButtonGroup group;
JLabel fNameLbl, lNameLbl, genderLbl, tempBtn, temp3, temp2, temp1;

public UserDialog3() {
    add(createForm(), BorderLayout.CENTER);
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    setLocation(400, 100);
    pack();
    setVisible(true);
}

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

public JPanel createForm() {
    JPanel panel = new JPanel();

    okBtn = new JButton("Ok");
    cancelBtn = new JButton("Cancel");
    tempBtn = new JLabel();
    fNameLbl = new JLabel("First Name");
    lNameLbl = new JLabel("Last Name");
    genderLbl = new JLabel("Gender");
    temp2 = new JLabel();
    temp1 = new JLabel();

    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(temp1);
    panel.add(lNameLbl);
    panel.add(lNameTf);
    panel.add(temp2);
    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;
}

@Override
public void actionPerformed(ActionEvent e) {

}

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);
        }
        return true;
    }
}
}
Sajad
  • 2,273
  • 11
  • 49
  • 92
  • So what is the question? – jzd Oct 24 '13 at 12:27
  • @jzd the question is that how can i enable radio buttons by clicking on it? – Sajad Oct 24 '13 at 12:31
  • when your first Name input field is wrong, it should not let you to go to last name field. Isn't it ? – Sage Oct 24 '13 at 12:32
  • Then why you are saying that last name field is correct but radio button is disabled ? – Sage Oct 24 '13 at 12:33
  • @Sage When user enter a wrong value at first time (on second text field), Then radio buttons disable correctly, and when user edit that wrong value to a correct value, he/she have to press `tab` button to enable radio buttons to select one of them. I want to make a change that user can enable radio buttons by clicking on them. – Sajad Oct 24 '13 at 12:38
  • @Sajjad As the [documentation says](http://docs.oracle.com/javase/7/docs/api/javax/swing/InputVerifier.html#verify(javax.swing.JComponent)) `verify` *"should have no side effects"* - The problem is, you are modifying the state of another component from within the `verify` method – MadProgrammer Oct 24 '13 at 23:16

1 Answers1

0

The purpose of InputVerifier class is to help clients support smooth focus navigation through GUIs with text fields. Before focus is transfered to another Swing component that requests it, the input verifier's shouldYieldFocus method is called(which ask the verify function to validate data). Focus is transfered only if that method returns true.

Please Try to fix the issues about using InutVerifier, verify and shouldYieldFunction as mentioned in your previous post. If you are not going to change your practice, you will be danger in future. Remove you components enabling and disabling code from verify function.

Your Problem in this post: In this case, what really happening is that, when your data is invalid and you try to lose your input text field focus by clicking another component, your JRadioButtons get disabled. A disabled cant be focused until it is re-enabled. As input-verifier responds with focus-lose event, clicking on the disabled RadioButton isn't resulting in focus navigation, and thus ShouldYieldFocus(which calls verify) is not being called to re-enable your components.

Pressing the tab works, because it is sending the Focus to your second text input field according to swing's focus traversal policy. Hence a focus lose event occur on first input text field and this time InputVerifier's verify function get called which eventually enables your component. To understand the problem better, try rewriting your own example with one JRadioButton and one JTextFeild.


Try using a DocumentListener with your text Field. upon data insertion and removal event, check your data validity using InputVerifier and then, enable/disable related components.

I am writing a sample code snippets to demonstrate, how adding DocumentListener to your fNameTF and lNameTF text fields will resolve your problem:

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

            @Override
            public void insertUpdate(DocumentEvent e) {
              doOnDataValidity(verifier.verify(fNameTF));
           }

            @Override
            public void removeUpdate(DocumentEvent e) {
               doOnDataValidity(verifier.verify(fNameTF));
            }

            @Override
            public void changedUpdate(DocumentEvent e) {}
        });

doOnValidity(boolean isValid) function is as follows:

public void doOnDataValidity(boolean isDataValid)
    {
         if(isDataValid) 
         {
            //enable your components 
         }else 
          {
              //disable your components
          }
    }

Add a DocumentListener to your lNameTf.getDocument() the same way.

Tutorial Resources: How to use DocumentListener.

Community
  • 1
  • 1
Sage
  • 15,290
  • 3
  • 33
  • 38
  • The [JavaDocs](http://docs.oracle.com/javase/7/docs/api/javax/swing/InputVerifier.html#verify(javax.swing.JComponent)) state that the `verify` method *"should have no side effects"*. The OP is changing the state of other components within the `verify` method, this is the actual problem. Instead the OP should be encouraged to use a different means for determining if component states should be changed, such as `PropertyChangeListener` for example - IMHO - The other problem is, while I like `DocumentFilter`s and wouldn't argue against there use in this context, it doesn't solve the problem – MadProgrammer Oct 24 '13 at 23:20
  • I'd also be considered over the use of a single `InputVerifier` for multiple components where the logic is the same for each field... – MadProgrammer Oct 24 '13 at 23:22
  • @MadProgrammer, i have already explained in details in [his another question](http://stackoverflow.com/questions/19499692/inputverifier-dont-display-each-component-iconlable) about `verify` and `shouldYeildFocus` function. Also about how could he use single input verifier. That is why i skipped those in this post. – Sage Oct 24 '13 at 23:32
  • However, In this post Though i have indicated that it is not preferable solution: `mixing verifier with document listener`. But i myself keep asking question if verifier's verify function is public, why it would be a problem using it to verify and then use that condition to enable or disable components inside the insertion and removal action context of `DocumentListener` ? At the very least as **it has the support for not letting the input field losing focus until data is valid!** – Sage Oct 24 '13 at 23:34
  • If you've provide suggest in a previous post to the OP, I would provide a link to them, as it helps build context. The next question is, is it appropriate to change the state of other components from within the context of the `DocumentFilter`? Is the `DocumentFilter` stepping outside of it's area of responsibility in doing so? IMHO I'd be trying to find some means by which I could provide notification about the changes, maybe even via a `DocumentListener` so as to de-couple the validation of the field from the rest of the application requirements, but that's me – MadProgrammer Oct 24 '13 at 23:44
  • No, that is me too. So, you think that mixing **`InputVerifier`** with **`DocumentListener`** is OK while enabling and disabling or notifying components will be done in insert and removal event context of it, as i have indicated in the post. I mean i myself is thinking that from the moment i have written this post. First i approached to imply on using `DocumentFilter` then i have edited the answer to use InputVerifer with **DocumentListener**. Please, I know i am bothering you. And I will update the answer linking OP's previous post. Thanks for the suggestion – Sage Oct 25 '13 at 00:04
  • 1
    I think the `InputVerifier` is responsible for determining the validity of the component it is past, that is all. It is the responsibility of the controller to determine the states of the components based on changes to the any given field, via their respective models/listeners...IMHO ;) – MadProgrammer Oct 25 '13 at 00:08
  • @Sage So, should are you recommend me to use a `mixing verifier with document listener` ? , Can i enable my disabled component state by clicking with `shouldYeildFocus` method/ – Sajad Oct 25 '13 at 18:14
  • @Sajjad, look into the example. This time don't touch the shouldYieldFocus. Enable/disable your component inside the DocumentListener insert and removal function. Because shouldYieldFocus only works when component loses its focus. But you need to enable/disable component on every change in data of textcomponent – Sage Oct 25 '13 at 21:08