how to Override FocusListener - Swing - java

The application i work with override the default JComboBox from swing. Leets Call it MyComboBox. This version of ComboBox implement the FocusListener and contains the two methods focusGained and focusLost.
Now, in one of the panel of the application, the form contains a ComboBox of this type:
MyComboBox aMyComboBox = new MyComboBox();
I want to add a listener on this like that :
aMyComboBox.addFocusListener(new FocusListener() {
public void focusLost(FocusEvent e) {
//Do something here
}
public void focusGained(FocusEvent e) {
//Do something else
}
});
But when i run the code, it never pass into these method but only execute the focusGained/lost from the MyComboBox class.
Is there a way to add a listener on an object that already implements FocusListener?

Additional FocusListener should work unless the instance used in MyComboBox consumes the event (AWT event consumption).
Try making an example with an ordinary JComboBox -- this will help narrowing down the cause of the problem.

Related

How do I register an object's event listener to an event handler outside its class?

I have 2 classes, one JFrame class and one JButton class called LightsOutButton. The JFrame class has a collection of these LightsOutButton objects. I need to do actions when the individual buttons are pressed, but I can't access the JFrame class's methods from the event handler in my LightsOutButton class.
It seems like the best way to work around this would be to register each button with the JFrame class's event handler. How would I do that?
`// this is my button object. It has registered its action listener to itself(which I want to change)
public class LightsOutButton extends JButton implements ActionListener {
private boolean onOrOff; // true = on, false = off
private int iCoord;
private int jCoord;
public LightsOutButton() {
super.addActionListener(this);
onOrOff = false;
super.setContentAreaFilled(false);
}
}
// this is my JFrame class. This is the class that I want to handle each button object's events
public void actionPerformed(ActionEvent e) {
// Get the button that was clicked
JButton button = (JButton)e.getSource();
if(button == newGame) {
reset();
}
if(button == manual) {
if (manualMode == false) {
manualMode = true;
}
if (manualMode == true) {
manualMode = false;
}
}
// this is the implementation that I'm wishing for here:
if(button = LightsOutButton){
// do something
}
}`
Basically as I understand it, you have a group of LightsOutButton which have been added to a JFrame. In LightsOutButton you are trying to perform some action, but need to access the JFrame in some way to achieve it...
I would say you have the wrong concept. Sure, there's no reason why LightsOutButton can't have it's own event handlers to manage it's internal state, but beyond that, it shouldn't be concerned about anybody else.
It seems like the best way to work around this would be to register each button with the JFrame class's event handle
Would be an accurate assessment. How you do it will depend on how you've managed your code, but probably the simplest would be to add the LightsOutButtons to some kind of List or array and add and register the handler from within a loop.
Identification of each light will be your next problem, but you could use the reference from the List/array, or set the name property of each light or the actionCommand property depending on your needs.
If each light has a "particular" task to do, you could consider using a Action or specialised ActionListener for each one, but that comes down to needs
in your JFrame class, when you add you buttons
LightsOutButton b = new LightsButton(..);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//you have acces to JFrame methods ..
});

Can't get ItemListener to work for JCheckBox

I am using this code to create a JCheckBox
private final JCheckBox cbDisplayMessage = new JCheckBox("Display");
cbDisplayMessage.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getItemSelectable() == cbDisplayMessage) {
if(cbDisplayMessage.isSelected()) {
cbDisplayMessage.setSelected(false);
} else {
cbDisplayMessage.setSelected(true);
}
}
}
});
When I run this it causes an StackOverflow error on setSelected(true). Can't figure out what I am doing wrong. Any ideas appreciated....
You can try with ActionListener instead of ItemListener as shown below without causing StackOverflow error.
cbDisplayMessage.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (cbDisplayMessage.isSelected()) {
cbDisplayMessage.setSelected(false);
} else {
cbDisplayMessage.setSelected(true);
}
}
});
There is no need to check the source of the event again because you are sure that you have added this listener on the same object. This is required only if same listener is added for more components.
-- EDIT--
Now Your requirement is clear to me. If you want to toggle the state of the check box then there is no need to do it using listener because that's the default behavior of the check box.
Your listener is called every time the state changes, but you trigger a new state change from within that listener, so each state change results in that listener being called over and over again until your stack is full. Your setup has to be a bit more complicated to do something like that - if you want to change the state of the component you're listening to, you'll want to remove its listener(s), fire your programmatic state change, then re-add them.

What is the difference between having common or separate actionPerfomed method

Please help me understanding the difference between adding the action listener to JComponent in following two approaches.
First Method: Implementing actionListener to my class and adding the common actionPerformed method which choose selection based on the events
class Test implements ActionListener
{
JButton jbutton = null;
public Test(){
jbutton = new JButton();
jbutton.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
//Perform operation here;
}
}
Second Method: Defining the action listener for individual JComponent.
JButton jbutton = new JButton();
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//Perform operation here
}
});
What is the difference between these two approach and which one is more cleaner and maintainable approach and if there is any efficiency benefit involved ?
I'd go with the first approach if:
The action is fired via different events. For example, you have an action that changes the language of the GUI from English to Arabic (where you need to re-arrange the components to lay from right to left) and that action can be fired via some key bindings like (Alt + R) and via a JMenuItem, and maybe via some buttons.
Several actions have the same base code. For example, a calculator application where each math operation button would fire the same action and based on the action command you can determine the operation from inside actionPerformd(). They share the GUI updates.
and I'd go with the second approach if:
The action is tied to only one event and you want to write it on the fly.
What I wouldn't do is something similar to this:
public class MainFrame extends JFrame implements ActionListener
but I would write:
public class CustomListener implements ActionListener
Also see:
Best practice for implementing ActionListener
best practice for gui and actionlistener
ActionListener best practices
Nested class vs implements ActionListener
Organize Code for GUI and ActionListener in Java
define button actions in inner class Vs define button actions in public class in swing
What is better to use: Action vs ActionListener?

Automatic Updating of Action's isEnabled()

I have written a Swing GUI with several controls associated with the same Action subclass. The implementation of the Action subclass follows this psudocode:
public class MyGUI
{
Gizmo gizmo_; // Defined elsewhere
public class Action_StartPlayback extends AbstractAction
{
/* ctor */
public Action_StartPlayback(String text, ImageIcon icon, String desc, Integer mnem)
{
super(text, icon);
putValue(SHORT_DESCRIPTION, desc);
putValue(MNEMONIC_KEY, mnem);
}
#Override public boolean isEnabled()
{
return gizmo_ == null;
}
#Override public void actionPerformed(ActionEvent e)
{
gizmo_ = new Gizmo();
}
Action_StartPlayback act_;
};
The action is associated with both a button and a menu item, in a way similar to this psudocode:
act_ = new Action_StartPlayback(/*...*/);
// ...
JButton btn = new JButton(act_);
JMenu mnu = new JMenu(act_);
When I click the button or the menu item, the action's actionPerformed is fired correctly, gizmo_ is initialized and is non-null and everything works as expected -- except that the button and menu item are still enabled.
I expected that isEnabled would have been called again "automagically" but this is obviously not happening. isEnabled() is never called again.
This evokes two questions:
Is it OK for me to #Override the isEnabled() method as I have done here?
Assuming the answer to #1 is yes, how do I trigger a refresh of the GUI so that isEnabled() is called again, resulting in the button & menu item being disabled?
Instead of overriding setEnabled you could simply call setEnabled(false) after you intitialize your gizmo in your actionPerformed method:
#Override public void actionPerformed(ActionEvent e)
{
gizmo_ = new Gizmo();
setEnabled(false);
}
Here's the setEnabled implementation from AbstractAction:
public void setEnabled(boolean newValue) {
boolean oldValue = this.enabled;
if (oldValue != newValue) {
this.enabled = newValue;
firePropertyChange("enabled",
Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
}
}
The automagical you're looking for is the call to firePropertyChange, which notifies components based on this action that the state has changed, so the component can update its own state accordingly.
I am no pro at this, but I don't see a see an automatic way of doing this, of notifying listeners that the state of enabled has changed. Of course you can call setEnabled(false) at the start of the actionPerformed, and then code Gizmo (or a wrapper on Gizmo) to have property change support and then add a PropertyChangeListener to Gizmo, and in that listener, when the state changes to DONE, call setEnabled(true). A bit kludgy but it would work.
This is not strictly limited to Swing, but a more general Java principle. A lot of classes in the JDK (and in other libraries) have a getter and a setter for a property. Those methods are not meant to be overridden to return a dynamic value as most of the times the superclass accesses the corresponding field directly and does not go through the getters.
If you have dynamic behavior, you should call the corresponding setter each time the value changes. This will notify the super class changes have been made, and typically this will also fire a property change event to notify other interested parties.
You can find a bit more on this convention if you do a search on Java beans.
In your case, a possible solution is to let your UI class fire a PropertyChangeEvent when that gizmo instance changes, and let your actions listen for that event. When they receive such an event, they update their own enabled state.
The enabled-state is stored in both of your objects, in the AbstractAction and in the JButton.
This is important because you only need one instance of Action_StartPlayback for multiple Components like:
In the menu's button.
In a toolbar.
In a Shortcut Strgp in example.
All of them can have the same instance of Action_startPlayback. The Action_startPlayback is the only source of truth. The components are responsible to respect this source of truth so every Component will ask the AbstractAction to notify them if something has been changed. The AbstractAction will remember all the components and will notify them using the Method firePropertyChange().
But how to repaint all pending components? You must force all pending Components to ask the Action_startPlayback for the actuall enabled-state! Look at this:
#Override public void actionPerformed(ActionEvent e)
{
gizmo_ = new Gizmo();
// now, force the components to get notified.
setEnabled(true);
}

Using Actions with DocumentListener

I'm developing an application where I want something to be triggered both by the user updating the contents of a JTextArea, or manually via pressing a JButton.
I have done the first part using a DocumentListener and putting the relevant code in its insertUpdate method.
I haven't used Actions before, but I've heard they are useful for situations where you need something to be triggered by multiple controls. Is it possible to trigger the action from the DocumentListener? Is it a good idea to use Actions at all, or should I just put my code in a normal method?
(in the constructor):
textAreaInput.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
// do something
}
public void removeUpdate(DocumentEvent e) {}
public void changedUpdate(DocumentEvent e) {}
});
and the Action, which is a field:
Action doSomething = new AbstractAction("Do Something!") {
#Override
public void actionPerformed(ActionEvent e) {
// do it
}
};
clarification:
The JTextArea will receive text that is pasted in by the user, which I want to parse automatically. The parsing depends on other values set elsewhere in the GUI; if the user changes these other values, he may want to re-parse the text, hence the need to perform the same action by pressing a button.
I want something to be triggered both by the user updating the contents of a JTextArea, or manually via pressing a JButton.
This doesn't make sense to me.
Why would clicking a button invoke the same Action as a user typing text into a text area?
I haven't used Actions before, but I've heard they are useful for situations where you need something to be triggered by multiple controls
That statement is meant for controls that the user clicks, like JMenuItems, JButtons or hitting Enter on a text field. In general they can be used when you use an ActionListner.
A DocumentListener is not an ActionListener so as I stated earlier the use of an Action doesn't seem appropriate.
I think you need to clarify your requirement.
Edit, based on clarification
if the user changes these other values, he may want to re-parse the text
Why does the user have a choice? If you change the font, text, foreground, background of a text area, the component it automatically repainting, you don't have to ask for this to be done. If you look at the code for these methods they always end up invoking the revalidate() and repaint() methods.
The parsing depends on other values set elsewhere in the GUI;
Sounds like you need a custom class. Maybe a ParsedTextArea or ParsedDocument. This class would contain the "properties" that can be set elsewhere in the GUI. It would implmenent the DocumentListener. It would also support your "parseTheText" method. So whenever a property is changed or a DocumentEvent is generated you automatically invoked the "parseTheText" method. This way you don't need a separate button and the component will always be in sync because the parsing is automatic.
You can invoke the actionPerformed() method, whether it's in an Action or not. There's an example here.
I think you need not create the Action object. You can add ActionListener to the Button just like you have added DocumentListener to the Document of the input. If I correctly understand your problem, may be you should do something like this:
textInput.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void insertUpdate(DocumentEvent e) {
doIt();
}
#Override
public void removeUpdate(DocumentEvent e) {}
#Override
public void changedUpdate(DocumentEvent e) {}
});
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
doIt();
}
});
doIt() is a method in which you will do what you wanted to do.

Categories