J2SE 版本 1.4 中新增了一項有趣的 Swing 功能。Swing 控件現在可以提供聽覺反饋來對特定事件作出響應,不過缺省情況下這項功能是禁用的。新增的這項功能有助於 Swing 控件更好地模仿系統本地操作系統的控件的行為。
聽覺基本知識
Swing 使用一種可插式外觀和感覺(Pluggable Look-and-Feel,PLAF)體系結構。開發者不必針對不同組件為顏色和字體之類的設置進行硬編碼;取而代之的是,組件將從用戶界面管理器(User Interface(UI)Manager)請求這些設置。作為開發者,您可以告訴 UI 管理器要讓用戶看到什麼樣的界面;您可以選擇 Windows、Motif 或 Metal 樣式等。UI 管理器接下來就可以實際告訴每個組件應該如何顯示它自身。對於象按鈕這樣的組件來說,前景顏色是通過設置 Button.foreground 屬性來控制的,如下所示:
UIManager.put("Button.foreground", Color.red);
在這裡, Button.foreground 為用戶界面屬性名,而 Color.red 代表特定的設置。改變了設置之後,所有新的按鈕的前景顏色都將是紅色。(也有方法可以改變以前創建的按鈕的前景顏色。)雖然不同的預置外觀和感覺為這些設置提供了缺省值,您還是可以重設它們。
在 J2SE 1.4 下,您可以用類似的方式來啟用聽覺反饋。您只要了解 UI 屬性名和合適的設置就可以了。屬性在這裡被命名為 AuditoryCues.playList ,設置則為聽覺提示名稱的一個 String 數組。UI 管理器接下來將把這些名稱映射到特定操作發生時將播放的聲音文件。
下面將給出系統提供的外觀和感覺中所支持的聲音列表。它們的名稱本身就頗具解釋性。
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
提供給 AuditoryCues.playList 屬性的 String 名稱數組就是這樣 ― 一個事件 名稱的集合。UI 管理器負責將這些名稱映射到特定於外觀和感覺的聲音。
您可以從這些名稱中手動地創建一個真正希望支持的事件名稱的數組,不過這並不是必需的。值得慶幸的是,對於常用的組來說已經有兩個系統定義過的設置可以使用,還有一個設置可以用於 Metal 外觀和感覺。
這些設置提供了一個查找鍵 AuditoryCues.allAuditoryCues ,它允許您從 UI 管理器查找適用於所有聲音的數組。一旦您查找了這個數組,就可以用 AuditoryCues.playList 鍵將其存儲在 UI 管理器中,如下所示:
UIManager.put("AuditoryCues.playList",
UIManager.get("AuditoryCues.allAuditoryCues"));
您還可以使用另外兩個查找鍵: AuditoryCues.noAuditoryCues ,即無聲,還有 AuditoryCues.defaultCueList ,它只為四種 OptionPane 設置播放聲音提示,專門用於 Metal 外觀和感覺。
一旦您改變了 AuditoryCues.playList 設置,就可以使用一組新的聲音提示了。當特定操作發生時,UI 管理器將檢查播放列表,尋找與該操作關聯的鍵。UI 管理器接下來將使用這個鍵來查找要載入並播放的聲音文件。如果提示(cue)數組中不存在任何鍵,就不會播放任何聲音。
如果您不喜歡某個聲音,可以通過將其提示名映射到另一個文件來替換它。舉例來說,在下面的代碼中,您將看到“問題(question)”聲音被映射到系統提供的“錯誤(error)”聲音文件:
UIManager.put("OptionPane.questionSound", "sounds/OptionPaneError.wav");
這就是在 Swing 程序中播放與預先定義好的操作關聯的聽覺提示所涉及的所有內容。
完整示例
為了展示我們剛才描述過的功能,清單 1 中的程序將顯示三個單選按鈕,讓您選擇希望使用三種提示設置中的哪一種。您可以參看圖 1 中簡單的用戶界面。
圖 1. 示例應用程序界面
程序還顯示了兩個顯示彈出窗口的按鈕。啟用後,顯示彈出窗口的操作將觸發聲音提示。請您自己將確認對話框出現時播放“ 錯誤”聲音文件的代碼行標記出來。
清單 1. 聲音示例
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();
}
}