2

There's a text field and when lost focus it will validate the inputs, if not passed, print out the error message (to be simple here just has an empty check). And there's a button next to the text field, it will print out the text once click on it.

As I tried, when input some text and then click the button it will trigger both the focus lost event of text field and the event of button. In a other word, it will do the validation first and then print out the input text.

Here comes my question, what is the good approach to prevent printing out the text if the validation not passed? Or is there a way to "ignore" the click event on button if validation not passed?

I tried to use a boolean flag which indicate the validation result and check the flag when perform the action for button, but I do not think it is a good approach. As I know there's an event dispatcher thread in Swing which deal with the events, is it possible I can cancel the events from here?

Below is a piece of code which explain the question:

public class SimpleDemo
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel content = new JPanel(new FlowLayout());
        frame.setContentPane(content);

        final JTextField textField = new JTextField(10);
        textField.addFocusListener(new FocusAdapter()
        {
             @Override
             public void focusLost(FocusEvent e)
             {
                 String text = textField.getText();
                 // do some validation here, if not validated 
                 // do not trigger the event on button.
                 if ("".equals(text))
                 {
                     System.out.print("please input a text!");
                 }
             }
        });
        content.add(textField);

        JButton button = new JButton("Print Text");
        button.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                // action performed for button
                String text = textField.getText();
                System.out.println(text);
            }
        });
        content.add(button);

        frame.setVisible(true);
        frame.pack();
    }
}
Aaron
  • 573
  • 1
  • 5
  • 15
  • consider using an InputVerifier (instead of the low-level focusListener) - [validation example](http://stackoverflow.com/a/14041811/203657) – kleopatra Mar 28 '13 at 11:26
  • @kleopatra I tried with InputVerifier but seems the button can not bounced up after showing the error message, could you check my latest code and give suggestion? – Aaron Mar 28 '13 at 14:37
  • 1
    didn't see your not-an-answer before (yet another reason you shouldn't post clarifications/follow-ups to your question in the answer section :-). Fix your implementation of InputVerifier and check if the button still is stuck (there had been a bug in earlier jdks, so it might) – kleopatra Mar 28 '13 at 14:50
  • For [example](http://stackoverflow.com/q/11818080/230513). – trashgod Mar 28 '13 at 16:25

3 Answers3

1

I faces similar issue while working on an application. I solved it like below I created a abstract class ApplicationFrame which every frame in the application extends

public abstract class ApplicationFrame extends JFrame implements ActionListener {
    @Override
    final public void actionPerformed(ActionEvent event) {
        if(validateInput()){
             performAction(event);
        }
    }

    /*
    * Sub class should override this method to receive any action
    */
    protected void performAction(ActionEvent event) {};

    /*
     * Sub class should override this method to perform validation
    */
    abstract protected boolean validateInput();
}

All Frames will now extend this base frame, as below:

public class Frame1 extends ApplicationFrame{
    @Override
    protected void performAction(ActionEvent event) {
        // perform action
    }
    @Override
    protected boolean validateInput() {
        // return true or false depending upon the validation results
    }
    // if you want to add Action Listener, you need to add like this:
    btnSomeButton.addActionListener(this);
}

If you need to handle Focus events, you can make ApplicationFrame or the base frame implement FocusListener. This is my custom implementation to solve the problem, hope this helps.

Apurv
  • 3,723
  • 3
  • 30
  • 51
0
  • Make the button disabled on start-up
  • Upon lost focus, validate the text & enable button only when the input passes validation.
  • Upon start of text change, disable the button
R Kaja Mohideen
  • 909
  • 1
  • 8
  • 24
0

It's always makes sense to make ui to communicate with user. So you can show "please input a text" as the default text of the textField when nothing is entered by user. Here is the code for such custom textField:

public class TextFieldWithDefaultText extends JTextField implements FocusListener{

private final String hint;

public TextFieldWithDefaultText (String $text)
{
    super($text);
    this.hint = $text;
    addFocusListener(this);
}

@Override
public void focusGained (FocusEvent $e)
{
    if (this.getText().isEmpty())
    {
        super.setText("");
    }
}

@Override
public void focusLost (FocusEvent $e)
{
    if (this.getText().isEmpty())
    {
        super.setText(hint);
    }
}

@Override
public String getText ()
{
    String typed = super.getText();
    return typed.equals(hint) ? "" : typed;
}

}

Write the acttionListerner for your button like this:

JButton button = new JButton("Print Text");
    button.addActionListener(new ActionListener()
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            if(!textField.getText().isEmpty())
                System.out.println(textField.getText());
        }
    });

And ur textField implementation should be :

final TextFieldWithDefaultText textField = new TextFieldWithDefaultText ("please input a text");

Hope this helps :)

E V
  • 43
  • 1
  • 7
  • Thanks for answering. I agree with you, but the question bothers me is how to "ignore" the events. :) – Aaron Mar 28 '13 at 13:43
  • Actually I was ignoring the event by checking the condition of if(!textField.getText().isEmpty()). But if you want to completely avoid events to be passed to java eventQueue, I am afraid it's not possible. Handling of manual events for UI is done using Java native peers. So you check for a condition in actionPerformed() method if u want to ignore it. I know it's a kind of hack :) – E V Apr 01 '13 at 06:17
  • If you think it answers your question, please don't forget to select it as answer :) – E V Apr 01 '13 at 06:18