Understanding Action Objects in Java, Page 5
Listing 14 invokes the setAction method on the JButton object to register the other Action object on that JButton. Thus, two different Action objects are registered on the two JButton objects on the toolbar.
Synchronized with menu items
Furthermore, the same two Action objects that are registered on the JButton objects on the tool bar are also registered on the two JMenuItem objects on the menu. Thus, the menu items and the toolbar buttons are tied together (in pairs) so as to behave in a synchronous fashion.
When one of the Action objects becomes disabled, the corresponding menu item and the corresponding toolbar button also become disabled. When the other Action object becomes disabled, the other menu item and the other toolbar button become disabled.
When an Action object becomes enabled, the corresponding menu item and the corresponding toolbar button become enabled.
When the value of the keyed property of an Action object identified with the key Action.SMALL_ICON changes, the corresponding menu item and the corresponding toolbar button track the change. This causes the image displayed on both of those components to change.
Various containers can be used
Probably the most common use of the Action interface is to synchronize the behavior of items on a menu with buttons on a toolbar. However, the use of the Action interface is not confined to those two types of containers. Rather, the Action interface can be used to synchronize the behavior of action-aware components in just about any kind of container. This is illustrated in Listing 15.
(You may want to avoid AWT containers to avoid the problems involved in mixing heavyweight and lightweight components. For example, it appears that you cannot control icons on a JButton that is placed in an AWT Panel.)
JButton butC = new JButton(); butC.setAction(actionObj01); panel.add(butC); JMenuItem mnuC = new JMenuItem(); mnuC.setAction(actionObj02); panel.add(mnuC); Listing 15 |
Populate the JPanel
Listing 15 creates a new JButton object and a new JMenuItem object and places them in a common JPanel container object. The setAction method is used, along with the same two Action objects discussed earlier, to synchronize the behavior of these two components with the two components on the menu, and the two components on the toolbar.
(Hopefully by now you will have compiled and run this program. Due to the limitations of my verbal descriptions of behavior, running the program may ultimately be necessary for you to fully understand how this program behaves.)Construct control panel, set size, etc.
Listing 16 constructs the control panel containing check boxes that
will be used to manipulate the properties of the two Action objects.
Listing 16 also sets the size of the GUI and makes it visible.
//Construct the control panel and
// put it in the Center
controlPanel.setLayout(
new GridLayout(2,2,3,3));
controlPanel.add(ckBox01);
controlPanel.add(ckBox02);
controlPanel.add(ckBox03);
controlPanel.add(ckBox04);
getContentPane().add(controlPanel,
BorderLayout.CENTER);
//Set the size and make the GUI
// visible
setSize(350,200);
setVisible(true);
setTitle("Copyright 2002, " +
"R.G.Baldwin");
Listing 16
|
The code in Listing 16 is completely straightforward and doesn't deserve further discussion in this article.
Register checkbox event handlers to manipulate Action properties
The anonymous inner listener class in Listing 17 makes it possible for the user to manipulate the enabled property of one of the Action objects and its associated visual components.
The code in Listing 17, (and the code that follows in other listings), registers ActionListener objects on each of the checkboxes.
(Note that these ActionListener objects registered on the checkboxes are completely independent of the Action objects registered on the action-aware components.)This control structure makes it possible for the user to disable and enable the two Action objects independently of one another simply by checking or clearing the checkboxes.
This control structure also makes it possible to toggle the icons between
two different images on each Action object when the Action
object is enabled.
ckBox01.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent e){
if(e.getActionCommand().
equals("Disable01")){
ckBox01.setText(
"Enable01");
actionObj01.setEnabled(
false);
//Disable ability to toggle
// the IconImage.
ckBox03.setEnabled(false);
}else{
ckBox01.setText(
"Disable01");
actionObj01.setEnabled(
true);
//Enable ability to toggle
// the IconImage.
ckBox03.setEnabled(true);
}//end else
}//end actionPerformed()
}//end ActionListener
);//end addActionListener
Listing 17
|
Two important statements
Although the code in Listing 17 appears to be long and complex, it is relatively straightforward.
The actionPerformed method shown in Listing 17 is invoked when the checkbox fires an action event (when the user checks or clears the checkbox). Let me draw your attention to the two boldface statements in Listing 17. These two statements use the current state of the checkbox object to make a decision between two alternatives, and then to change the value of the enabled property of the Action object referred to by actionObj01. (The state of the checkbox object is also changed accordingly.)
When the value of the enabled property of the Action object is changed, the three components registered earlier as change listeners on the Action object are notified of the change. The code in the classes from which those components were instantiated causes them to become enabled or disabled accordingly. In other words, the enabled state of all three components tracks the enabled property of the Action object.
The other Action object
The code in Listing 18 uses a different checkbox object to provide essentially
the same enabled/disabled control for the other Action object
and its associated components. Since this code replicates the code
in Listing 17, I deleted most of it for brevity. You can view all
of the code in Listing 22 near the end of this lesson.
ckBox02.addActionListener( //...code deleted for brevity );//end addActionListener Listing 18 |
Manipulate the icons
Listing 19 is an anonymous inner listener class that makes it possible for the user to manipulate a keyed property value of an Action object, the value of which specifies the icon to be displayed on registered components.
Basically, this code causes the value of the property that specifies
the icon displayed on the components to toggle between two different ImageIcon
objects based on two different gif files.
ckBox03.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent e){
//Get file name for the
// ImageIcon object.
String gif = (actionObj01.
getValue(
Action.SMALL_ICON)).
toString();
if((gif).equals(
"redball.gif")){
actionObj01.putValue(
Action.SMALL_ICON,
new ImageIcon(
"blueball.gif"));
}else{
actionObj01.putValue(
Action.SMALL_ICON,
new ImageIcon(
"redball.gif"));
}//end else
}//end actionPerformed()
}//end ActionListener
);//end addActionListener
Listing 19
|
Change the displayed icon
The logic in Listing 19 is straightforward. When the checkbox fires an action event, the code in the actionPerformed method uses the getValue method of the Action interface to get the name of the gif file that specifies the icon. Then it changes the value of that keyed property in the Action object to an ImageIcon object based on the other gif file, thereby toggling the value between two ImageIcon objects based on the two different gif files.
When the value of this keyed property changes, the three components that were earlier registered as change listeners on the Action object are notified of the change. The code in the classes from which the three components were instantiated causes the icon that is displayed on the component to track the corresponding property value of the Action object.
Do it again for the other Action object
Listing 20 provides the same icon toggling capability for the other
Action
object. Once again, since this code replicates the code in Listing
19, I deleted most of it for brevity. You can view all of the code
in Listing 22 near the end of this lesson.
ckBox04.addActionListener( //... code deleted for brevity );//end addActionListener Listing 20 |
Finally, the end of the program
Listing 21 is a simple WindowListener that terminates the program when
the user clicks the close button on the JFrame object.
This is relatively standard material, which should not require a discussion
in this context.
this.addWindowListener(
new WindowAdapter(){
public void windowClosing(
WindowEvent e){
System.exit(0);
}//end windowClosing()
}//end WindowAdapter
);//end addWindowListener
}//end constructor
}//end GUI class
Listing 21
|
Listing 21 is also the end of the GUI class definition.
Run the Program
(Note that you will need a couple of gif files containing small images to use as ImageIcon objects. Any small image will do. Just be sure to handle the file names properly.)
