Link to home
Start Free TrialLog in
Avatar of Calron
Calron

asked on

Preventing a JButton from being clicked

I have an application where I have to validate different fields. Before a field may lose the focus, the validation has to be performed and if it fails the field may not lose the focus. My problem is that whenever I have buttons on the form as well, these buttons can be clicked even though the validation failed and the button should not receive an actionEvent.
Is there a way to stop the button from receiving an actionPerformed event in the cases where the validation fails and the focus is not allowed to leave the edit field?
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

button.setEnabled(false);
Avatar of Calron
Calron

ASKER

No, that will not work, take the case where the field validate correctly then the button has to be available to be pressed. The second thing is the visuals, I can't have all components painted gray while validating the component and once the validation is done enable all of them again ....

I'll specifiy more in detail what has to happen on the UI's that I am setting up.

every component that can receive the focus has three events:
boolean requestEnter()
boolean validate()
boolean requestExit()

Before a component is allowed to receive the focus the requestEnter event has to be called. If it returns true, the component may receive the focus. Before losing the focus, validate is called and if that is true, requestExit is called. If both of these return true then the component can lose the focus and the next component is focused.

Disabling components will not work, because they will not be available in the focus chain to receive the focus once the validate and requestEnter both returned true.
>> Is there a way to stop the button from receiving an actionPerformed event
Isn't it enough to - if actionPerformed() is triggered in that specific case - just return
without performing the instructions you should normally perform in actionPerformed()?
>>No, that will not work, take the case where the field validate correctly then the button has to be available to be pressed.

Why not?

boolean fieldWasValid = ..... // (do the validation)
button.setEnabled(fieldWasValid);
Avatar of Calron

ASKER

The proble is that I have to set up a system that will handle a whole range of UI's. I have no control over what the other programmers later add into their actionPerformed events.  They are just expecting the events that I described above, and if the actionPerformed is called, they of course expect that the validation and the other events executed correctly. (even the button can have a requestEnter event :(  )
See my last comment.

>>I can't have all components painted gray while validating the component and once the validation is done enable all of them again

That's not necessary.

a. Only the button that you need to disable needs to be affected
b. It only gets disabled (grayed out) if the validation fails and not otherwise
Avatar of Calron

ASKER

>>  a. Only the button that you need to disable needs to be affected

I have no idea which button will be pressed, since any range of UI's have to work with this system I have no idea how many buttons are on that UI without actually getting all components and filtering out the buttons. Also I would have to filter out all JComboBoxes too, since if a field validation fails I can't allow a user to choose a new setting in a COmbobox either, etc.

>>  b. It only gets disabled (grayed out) if the validation fails and not otherwise

once again impractical. It may work disabling all the buttons if a validation fails, but what if the user then corrects the mistake and attempts to leave the field?I then have to go and enable all the buttons and everything else that should not have been activated.
ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Read my comment?

What about the idea:

boolean b = myButton.validate()

public void actionPerformed( ... ) {
    if (!b) return;

    // Perform the other stuff
}
Avatar of Calron

ASKER

zzynx: yes, I read your comment, and no, that is not an option, since I have to set up a system that other programmers will use and thus I can't interfere with the code that they put into their actionPerformed staements .....

CEHJ: I'll look into that. I have not heard about pane layering. I'll post again when I tried it out.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Calron

ASKER

The glasspane is certainly looking good. I will run some more tests tomorrow and get back to you. Thanks
OK
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
How do you know which fields need to be valid for a button to be enabled?
Avatar of Calron

ASKER

>> the glasspane won't intercept actionevents.

I saw that too, so the only way to work using glasspanels would be trapping the keyboard events and the mouse click events :(  not really a nice thing.

>>  How do you know which fields need to be valid for a button to be enabled?

As I described above. a component, lets say a textfield, has the focus, the suer is entering something and then leaves the field either through keyboardnavigation or through mouse navigation (clicking somewhere else). The framework I have to set up then has to call validate() on the textfield and if that method returns true, call requestExit() and if that is true the focus change and whatever activity the change effected can be executed.


I have had a version that seemed to work more or less. I solved it by subclassing all the relevant J... component classes and having our own look and feel. Both of these things were not only done because of this framework.
Whenever a button would receive a click event, I would trap it in the OurButtonUI class and set a flag. If the button then received the focus I would check that flag and if something was set, I would trigger actionPerformed. I did have one problem with this, one is that non-focusable buttons are never triggered (these are now requested for things like tool panels) and if a programmer used a normal JButton by mistake, it has to be clicked twice to be triggered.

That's the reason I am looking for better, i.e.. simpler ways to solve this
Avatar of Calron

ASKER

Using the glasspane to capture the events will probably work. I does add quite a lot of overhead to the whole thing though .... but then again, who said that life was easy :)

Seriously, I am currently trying to set up this system on a small scale to see if I can get the glasspane event trapping idea to work with what I have to set up. It does take a bit of time though....
Have u tried using FocusListeners?
Avatar of Calron

ASKER

Yes, what I did in a first version is overreide the addFocusListener() method on all our UI components.In the constructor I would then add a listener to a manager class that did the whole controlling of this event stuff. There I would check the what component would get the focus fire the events and then depending on the results of the events I owuld then fire the focusListeners that the programmers themselves added to the components.
The problem with this solution was the following:

Let's say that the focus is on textfield a, textfield b would be the next to receive the focus but is currently disabled. Leaving textfield a with tab, prompts my manager class and I see that textfield a has lost the focus and the focus went to textfield c. But, in the validate() call of textfield a, textfield b is enabled. This menas that textfield b should be getting the focus and not really textfield c. To solve that I used an internal list of components to determine which component would be the next component to receive the focus and send the focus to that field if possible (the event requestEnter() returned true).
The problem with solving it this way is that in some cases the FocusTraversalPolicy had a different component order than I had in my internal list and that definitely screwed up the whole thing.

What I am looking at now is creating my own KeyboardFocusManager where I handle this passing back and forth of the focus and calling the events. But of course I still have the problem with the buttons ....  that's why I posted here to see what possibilities there are to solve something like this, since I would like to ditch the version I described above with setting a flag on the button ....
Avatar of Calron

ASKER

In the end I found a way to solve this without using glasspanes (passing on the intercepted events to their specific targets would be more of a pain than it's worth). What I am doing now is in my subclass of JAButton, I overwrite the addActionListener method and hook up the actionListeners to a separate class. Now I can handle the actionevents in an internal class and only pass on the valid action events.

Thanks all for your input.
I'll be splitting the points between the three of you.
Glad you found a solution at last.
Illustration of "In coding everything is possible."
;°)

Thanks for accepting.