0

一位朋友最近要求我制作一个简单的 Buzzer 程序,并在我为他编写的内容中发现了一个奇怪的“错误”。

如果按下一个键并且蜂鸣器在几秒钟内快速复位,他会观察到在复位后的第一次按键和“蜂鸣”指示之间发生的 2 到 3 秒的程序冻结。他有以下 Java 安装:

build 1.7.0_25-b16

但是,我在我的计算机上没有遇到这个问题,安装了以下 Java:

$ java -version
java version "1.6.0_51"
Java(TM) SE Runtime Environment (build 1.6.0_51-b11-457-10M4509)
Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-457, mixed mode)

解冻后,程序会返回相应的键(即,不是最后按下的键,而是在重置之后和冻结之前按下的第一个键)。这表明问题不在于听者,而在于听者的反应。

关于可能导致这种现象的任何想法?在此先感谢您的帮助。

源代码:

/**
 * Buzzer.java
 *
 * Buzzer
 */
package org.lexingtonma.lhs.nhb;

import java.awt.Color;
import java.awt.DefaultKeyboardFocusManager;
import java.awt.Font;
import java.awt.KeyEventDispatcher;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;


/**
 * @author Arman D. Bilge
 *
 */
public class Buzzer extends JFrame implements KeyListener {

    private static final long serialVersionUID = 7492374642744742658L;
    private static final String BUZZ_A = "BuzzA.wav";
    private static final String BUZZ_B = "BuzzB.wav";
    private Clip buzz = null;
    private boolean listening = true;
    private final JTextField display = new JTextField(3);
    private final JButton reset = new JButton("Reset");

    {

        DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addKeyEventDispatcher(new KeyEventDispatcher() {
                public boolean dispatchKeyEvent(KeyEvent e) {
                    keyTyped(e);
                    return false;
                }
            });
        setTitle("Buzzer");
        final JPanel panel = new JPanel();
        setSize(256, 162);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        display.setFont(new Font("Helvetica", Font.BOLD, 64));
        display.setForeground(Color.WHITE);
        display.setVisible(true);
        display.setEditable(false);
        display.setHorizontalAlignment(JTextField.CENTER);
        panel.add(display);
        reset.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                display.setText("");
                display.setBackground(Color.WHITE);
                listening = true;
                reset.setEnabled(false);
            }
        });
        reset.setEnabled(false);
        panel.add(reset);
        add(panel);
        try {
            buzz = AudioSystem.getClip();
        } catch (LineUnavailableException e) {
            JOptionPane.showMessageDialog(this, e.getLocalizedMessage(), "FATAL ERROR", JOptionPane.ERROR_MESSAGE);
        }
    }

    public static final void main(String args[]) {
        Buzzer b = new Buzzer();
        b.setVisible(true);
    }

    public void keyPressed(KeyEvent e) {
        // Do nothing        
    }

    public void keyReleased(KeyEvent e) {
        // Do nothing        
    }

    public void keyTyped(KeyEvent e) {
        final char c = e.getKeyChar();
        if (listening && Character.isLetterOrDigit(c)) {
            buzz.close();
            listening = false;
            if (Character.isDigit(c)) {
                display.setBackground(Color.RED);
                try {
                    buzz.open(AudioSystem.getAudioInputStream(getClass().getResource(BUZZ_A)));
                    buzz.start();
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "FATAL ERROR", JOptionPane.ERROR_MESSAGE);
                    System.exit(1);
                }
            } else {
                display.setBackground(Color.BLUE);
                try {
                    buzz.open(AudioSystem.getAudioInputStream(getClass().getResource(BUZZ_B)));
                    buzz.start();
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "FATAL ERROR", JOptionPane.ERROR_MESSAGE);
                    System.exit(1);
                }
            }
            display.setText("" + c);
            reset.setEnabled(true);
        }

    }

}

罐子:https ://www.dropbox.com/s/62fl2i97m9hrx9m/Buzzer.jar

4

2 回答 2

2

每次创建一个新的 Clip 对象并丢弃旧的对象会更安全。试试这个方法

public static void play(String name) {
   try{
     AudioInputStream sounds = AudioSystem.getAudioInputStream(Buzzer.class.getResource(name));
     final Clip clip = AudioSystem.getClip();
     clip.addLineListener(new LineListener() {
         public void update(LineEvent e) {
             LineEvent.Type type = e.getType();
             if(type == type.STOP) clip.close();
         }
     });
     clip.open(sounds);
     clip.start();
   } catch(Exception e){
       e.printStackTrace();
   }

}

于 2013-10-06T02:48:37.190 回答
1

正如建议的那样,您可以尝试键绑定,看看它是否有帮助。这只是展示了如何使用 Enter 键。

public class Buzzer extends JFrame {
private static final String enter = "ENTER";
    public Buzzer() {
        // Key bound AbstractAction item
        enterAction = new EnterAction();
        // Gets the JFrame InputMap and pairs the key to the action
        this.getInputMap().put(KeyStroke.getKeyStroke(enter), "doEnterAction");
        // This line pairs the AbstractAction enterAction to the action "doEnterAction"
        this.getActionMap().put("doEnterAction", enterAction);
    }

    private class EnterAction extends AbstractAction {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Enter was pressed.");
        }
    }
}

实际上我不记得这在应用于 JFrame 时是否有效,您可能需要先制作一个 JPanel 才能将它们应用于。只需将“this”替换为面板名称即可。

于 2013-10-06T02:42:26.507 回答