 | Level: Introductory John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.
01 Jul 2002 The Swing architecture has traditionally provided a means for developers to create user interfaces for Java applications that mimic native UIs. The latest version of the Java 2 Platform, Standard Edition takes this idea a step further with a mechanism for associating feedback sounds with UI actions -- the kinds of beeps and clinks that users are accustomed to hearing out of their computer speakers. Though this functionality is turned off by default, John Zukowski shows you how to unlock its power in this latest edition of Magic with Merlin.
There's a new and interesting Swing feature in J2SE version 1.4. Swing controls can now provide auditory feedback in response to specific events, though this functionality is disabled by default. This added feature helps Swing controls better mimic the behavior of the controls of a system's native operating system. Auditory basics
Swing works with a Pluggable Look-and-Feel (PLAF) architecture. Developers needn't hard-code settings like color and font for the different components; instead, the components request these settings from the User Interface (UI) Manager. You, as the developer, can tell the UI Manager what interface you want the user to see; your options include Windows, Motif, or Metal styles, among others. The UI Manager then has the job of actually telling each component how it should display itself. For a component like a button, the foreground color is controlled by setting the Button.foreground property, as shown here:
UIManager.put("Button.foreground", Color.red);
|
Here, Button.foreground is the user interface property name and Color.red represents the specific setting. After you change the setting, all new buttons will have a red foreground color. (There's also a way to change previously created buttons.) While the different preset look-and-feels provide defaults for these settings, you can override them. Under J2SE 1.4, you can enable auditory feedback in a similar fashion. You just have to know the UI property name and appropriate settings. The property here is named AuditoryCues.playList and the setting is a String array of names for auditory cues. The UI Manager will then map these names to sound files that play when particular actions happen. The list of supported sounds in the system-provided look-and-feels are listed below. Their names are fairly self explanatory.
-
CheckBoxMenuItem.commandSound
-
InternalFrame.closeSound
-
InternalFrame.maximizeSound
-
InternalFrame.minimizeSound
-
InternalFrame.restoreDownSound
-
InternalFrame.restoreUpSound
-
MenuItem.commandSound
-
OptionPane.errorSound
-
OptionPane.informationSound
-
OptionPane.questionSound
-
OptionPane.warningSound
-
PopupMenu.popupSound
-
RadioButtonMenuItem.commandSound
The String array of names provided to the AuditoryCues.playList
property is just that -- a collection of names of events. It is the responsibility of the UI
Manager to map these names to sounds specific to the look-and-feel. You could manually create an array of the actual event names you want to support from these names, but that is unnecessary. Thankfully, there are two system-defined settings for commonly used groups, and a third available for the Metal look-and-feel. The settings provide a lookup key, AuditoryCues.allAuditoryCues, which allows you to look up the appropriate array for all the sounds from the UI Manager. Once you've looked up the array, you store it with the AuditoryCues.playList key within the UI Manager, as shown here:
UIManager.put("AuditoryCues.playList",
UIManager.get("AuditoryCues.allAuditoryCues"));
|
There are two other lookup key values available: AuditoryCues.noAuditoryCues, for no sound, and AuditoryCues.defaultCueList, which plays sound cues for just the four OptionPane settings and is specific to the Metal look-and-feel. Once you change the AuditoryCues.playList setting, the new set of audio
cues is available. When a particular action happens, the UI Manager examines the playlist for the key associated to the action. The UI Manager then uses that key to find the sound file to load and play. If no key is present in the cue array, no sound is played. If you don't like a particular sound, you can replace it by mapping its cue name to a different file. For instance, in the code below, you'll see the question sound mapped to the system-provided error sound file:
UIManager.put("OptionPane.questionSound", "sounds/OptionPaneError.wav");
|
That's all there is to playing auditory cues associated to predefined actions within your Swing programs.
A complete example
To demonstrate the capabilities we've just described, the program in Listing 1 presents three radio buttons that allow you to select which of the three cue settings you desire. You can see the simple user interface in Figure 1. Figure 1. Example application interface

Two buttons that display pop-up windows are also presented. The display of the pop-ups trigger audio cues when enabled. Feel free to comment out the line that plays the wrong sound file when the confirmation dialog appears. Listing 1. Audio example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Audio extends JFrame {
public Audio() {
super("Auditory Popups");
setDefaultCloseOperation(EXIT_ON_CLOSE);
UIManager.put("AuditoryCues.playList",
UIManager.get("AuditoryCues.defaultCueList"));
UIManager.put("OptionPane.questionSound",
"sounds/OptionPaneError.wav");
JPanel contentPane = (JPanel)this.getContentPane();
JPanel center = new JPanel();
ButtonGroup buttonGroup = new ButtonGroup();
JRadioButton defaultAudio = new JRadioButton("Default", true);
center.add(defaultAudio);
buttonGroup.add(defaultAudio);
defaultAudio.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
UIManager.put("AuditoryCues.playList",
UIManager.get("AuditoryCues.defaultCueList"));
}
});
JRadioButton offAudio = new JRadioButton("Off", false);
center.add(offAudio);
buttonGroup.add(offAudio);
offAudio.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
UIManager.put("AuditoryCues.playList",
UIManager.get("AuditoryCues.noAuditoryCues"));
}
});
JRadioButton onAudio = new JRadioButton("On", false);
center.add(onAudio);
buttonGroup.add(onAudio);
onAudio.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
UIManager.put("AuditoryCues.playList",
UIManager.get("AuditoryCues.allAuditoryCues"));
}
});
contentPane.add(center, BorderLayout.CENTER);
JButton confirmButton = new JButton("Confirmation Dialog");
contentPane.add(confirmButton, BorderLayout.SOUTH);
confirmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int result = JOptionPane.showConfirmDialog(Audio.this,
"Confirm?");
if (result == JOptionPane.YES_OPTION) {
JOptionPane.showMessageDialog(Audio.this, "Confirmed");
} else {
JOptionPane.showMessageDialog(Audio.this, "Rejected");
}
}
});
JButton messageButton = new JButton("Message Dialog");
contentPane.add(messageButton, BorderLayout.NORTH);
messageButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(Audio.this, "The Message");
}
});
this.pack();
show();
}
public static void main(String args[]) {
new Audio();
}
}
|
Resources
About the author
Rate this page
|  |