java - 显示 JOptionPane 窗口时使用 Windows 声音

标签 java windows swing awt joptionpane

例如,当我显示 JOptionPane.WARNING_MESSAGE 或显示 JOptionPane.ERROR_MESSAGE 时,我将如何播放用户设置的感叹声或错误声音?

最佳答案

我的假设 - 没有什么特别需要做的,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:但没有任何反应(并且假设被证明是错误的;-)

调试 session (我讨厌它......但偶尔......)结果并没有执行 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
           ....
        }

}

这很令人惊讶,不是吗?毕竟, Action 是创建的,所以如果没有播放列表,为什么要创建它们?

问题来了:用于创建 Action 的列表是不同的列表

// 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,

Oooookaaayy .. 让我们看看具体的 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"),

停产。

不完全 :-) 这个评论暗示了什么是可行的:

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

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

关于java - 显示 JOptionPane 窗口时使用 Windows 声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12128231/

相关文章:

java - 让两个JList同时滚动

java - NullPointerException - android.view.Window.findViewById(int) - 为什么?

c# - .NET 6 工作线程服务停止时出现错误

java - 如何在 Gui 中添加图形作为按钮面板下方的面板?

windows - 如何在 Windows 上重新居中事件程序?

java - 将生产 Android 应用程序从 Windows 7 正确移动/移植到基于 Linux 的系统

Java - 如何将组件的垂直列居中?

java - 一张一张地播放音频文件?

java - ISSUE : java.net.InetAddress RESULTS 与 MYSQL 结果相比是错误的

java - 在 Java 中,如何使用 JKS keystore 中的 X509 证书(公钥/私钥对)中的私钥进行解密?