在显示JOptionPane窗口时使用Windows声音

时间:2012-08-26 06:57:05

标签: java windows swing awt joptionpane

当我显示JOptionPane.WARNING_MESSAGE或显示JOptionPane.ERROR_MESSAGE时出现错误声音时,如何播放用户为感叹号设置的任何声音?

3 个答案:

答案 0 :(得分:3)

我的假设 - 没什么特别要做的,JOptionPane只是这样做 - 是基于略读BasicOptionPaneUI代码并检查是否安装了optionPane的audioActionMap。

播放音频的地方是在ui的propertyChangeListener中更改其祖先属性:

if ("ancestor" == e.getPropertyName()) {
    JOptionPane op = (JOptionPane)e.getSource();
    boolean isComingUp;

    // if the old value is null, then the JOptionPane is being
    // created since it didn't previously have an ancestor.
    if (e.getOldValue() == null) {
        isComingUp = true;
    } else {
        isComingUp = false;
    }

    // figure out what to do based on the message type
    switch (op.getMessageType()) {
    case JOptionPane.PLAIN_MESSAGE:
        if (isComingUp) {
            BasicLookAndFeel.playSound(optionPane,
                               "OptionPane.informationSound");
        }
        break;
    // all other message types handled as well
}

安装了共享的actionMap(懒惰,所以一个optionPane必须已经可见一次)

assertTrue(UIManager.get("AuditoryCues.actionMap") instanceof ActionMap);
ActionMap map = (ActionMap) UIManager.get("AuditoryCues.actionMap");
assertNotNull(map.get("OptionPane.errorSound"));

启用OS(win 7)级别的声音,硬件上的声音打开(仅用于测试)... WTF:但没有任何反应(并且假设被证明是错误的; - )

调试会话(我讨厌它......但偶尔......)结果是没有发生执行audioAction,这里涉及的方法如下:

static void playSound(JComponent c, Object actionKey) {
    LookAndFeel laf = UIManager.getLookAndFeel();
    if (laf instanceof BasicLookAndFeel) {
        ActionMap map = c.getActionMap();
        if (map != null) {
            Action audioAction = map.get(actionKey);
            if (audioAction != null) {
                // pass off firing the Action to a utility method
                // JW: we have an audioAction, so on to the next method
                ((BasicLookAndFeel)laf).playSound(audioAction);
            }
        }
    }
}

protected void playSound(Action audioAction) {
    if (audioAction != null) {
        Object[] audioStrings = (Object[])
                                UIManager.get("AuditoryCues.playList");
        if (audioStrings != null) {
           // JW: here the action is performed ... except we don't reach this
           ....
        }

}

那是相当惊人的,不是吗?毕竟,创建了动作,所以如果没有播放列表,为什么会创建它们呢?

接下来是:用于创建动作的列表是一个不同的列表

// in BasicLookAndFeel
protected ActionMap getAudioActionMap() {
    ActionMap audioActionMap = (ActionMap)UIManager.get(
                                          "AuditoryCues.actionMap");
    if (audioActionMap == null) {
        // here it's named cueList
        Object[] acList = (Object[])UIManager.get("AuditoryCues.cueList");

}

以及不同列表的原因是...允许LAF自定义实际播放的声音

// BasicLookAndFeel
// *** Auditory Feedback
"AuditoryCues.cueList", allAuditoryCues,
// this key defines which of the various cues to render.
// L&Fs that want auditory feedback NEED to override playList.
"AuditoryCues.playList", null,

Ooookaaayy ..所以让我们看看具体的LAF在做什么,f.i。赢:

// *** Auditory Feedback
// this key defines which of the various cues to render
// Overridden from BasicL&F. This L&F should play all sounds
// all the time. The infrastructure decides what to play.
// This is disabled until sound bugs can be resolved.
"AuditoryCues.playList", null, // table.get("AuditoryCues.cueList"),

EOL。

不完全:-)这条评论暗示了可行​​的方法:

Object[] cueList = (Object[]) UIManager.get("AuditoryCues.cueList");
UIManager.put("AuditoryCues.playList", cueList);

实际上它对WindowsLAF起作用(甚至尊重操作系统声音模式 - 最重要的是 - 如果禁用则播放),但不适用于任何其他核心LAF。

答案 1 :(得分:2)

首先,我同意安德鲁

但是,看看here然后here

我自己没有测试过这个

答案 2 :(得分:2)

使用MadProgrammer提供的链接(在最后重新发布)作为起点,这是我想出的:

import java.awt.*;
import javax.swing.JOptionPane;

//retrieve the default sound from windows system sounds
//for another sound replace "default" accordingly
    final Runnable SOUND = (Runnable)Toolkit.getDefaultToolkit().getDesktopProperty
    ("win.sound.default");

然后在显示JOptionPane之前:

if(SOUND != null)SOUND.run();

NB 无法以这种方式访问​​某些声音事件,如程序错误。 Oracle {/ 3}页面上的音频反馈标题下提供了可访问的声音事件列表

虽然这在非Windows操作系统上根本不起作用,但根据Windows Desktop Property Support,它不会导致程序在另一个操作系统上崩溃。我的Linux分区还没有JDK,因此我目前无法对此进行测试。