The project I’m working on right now is a virtual control panel, and I’m having a problem with animating an indicator light.
What I’m trying to do is to have a display that works like a simple indicator LED, in response to a message received from an outside system; it is specifically NOT supposed to react to mouse based selection. The indicator is defined as a jToggleButton, FWIW.
I have everything working as intended up to the point of changing the indicator graphic in response to the stimulus. I’ve tried unsuccessfully to define the graphic icons in the field properties page and have them change in response to isEnabled() or isSelected().
I’ve looked into using the graphics routines to paint the icons, but everytime I try to make sense of what I read, my eyes cross in befuddlement.
What I think I want to do is to generate a pre-loaded picture object for each of the two icons, and paint them at the proper place in response to the proper jToggleButton being selected via software call. Am I on the right track? In general terms, how do I accomplish this?
Make your class extend JLabel.
Have two static member variables:
static Icon _offIcon = new ImageIcon(MyClass.class.getResource("off-icon.gif"));
static Icon _onIcon = new ImageIcon(MyClass.class.getResource("on-icon.gif"));
Make sure you use getResource so that you are getting the icon from the classpath instead of the filesystem. Put the icon file in the same package as the class.
Add code like this:
private boolean _lightOn = false;
...
public boolean isLightOn(){
return _lightOn;
}
...
public void setLightOn(boolean value){
boolean oldValue = _lightOn;
if(oldValue != value){
_lightOn = value;
firePropertyChangeEvent("lightOn", oldValue, value);
updateFormState();
}
}
...
protected void updateFormState(){
this.setIcon(_ledOn ? _onIcon : _offIcon);
//...update other GUI stuff based on internal state
}
Now, when “setLightOn” is called, the GUI will be updated correctly.
You can add other things to “updateFormState” and then make sure to call it in any method that modifies the internal state of your object.
Make sure you are calling setLightOn from the GUI thread.
I wasn’t sure if you want it to be a button (since you said it shouldn’t respond to mouse clicks).
If you want it to be a button, extend JToggleButton and have the constructor add a change listener to the button that detects state changes. When the state changes, the listener should call “setLightOn” appropriately.
I finally got it to work, but my problem wasn’t in the graphics routines themselves. The variables in use were losing scope because of an implementation of a spawned thread I use to listen for communication with an external system. Once I figured that out, it was brain-dead simple…
Make sure you are doing everything that references Swing stuff from the GUI thread. It is extremely easy to accidentally violate this rule, and strange stuff can result.
A common trap: Make sure that the app is kicked off in the GUI thread (most examples violate this).
public class MyApp{
...
public static void main(String[] args){
Runnable runnable = new Runnable(){
public void run(){
new MyApp();
}
};
SwingUtils.invokeLater(runnable);
}
}
By doing this, you guarantee that all initialization code is run in the GUI thread.