例如,当我显示JOptionPane.WARNING_MESSAGE
或者显示JOptionPane.WARNING_MESSAGE
的错误声音,我将如何播放用户设置为感叹号的声音?
首先,我同意安德鲁
但是, 在 这里看看这里
Ps我没有测试过这个我自己
我的假设 – 没有什么特别的要求,JOptionPane只是做了它 – 基于浏览BasicOptionPaneUI代码并检查是否安装了optionPane的audioActionMap。
音频播放的位置在ui的propertyChangelistner中,对其祖先属性进行更改:
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"));
声音启用操作系统(赢得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在做什么,Win:
// *** 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。
使用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();
注意某些声音事件(如程序错误)无法以此方式访问。 在Oracle的Windows桌面属性支持页面的音频反馈标题下可以找到可访问的声音事件列表
虽然这在非Windows的操作系统上根本不起作用,但根据博客的说法,这不会导致程序在另一个操作系统上崩溃。 我的Linux分区还没有JDK
,我目前无法测试这个。