我正在努力解决使用TinySound(http://finnkuusisto.github.io/TinySound/)的问题。我已经制作了播放声音的方法(我已经实现了Music类,因为它允许在没有线程睡眠限制器的情况下播放)。我的问题是我的GUI中的“播放”按钮可能被垃圾邮件,导致声音或音乐在堆栈中播放。我已经检查了Java API中的setMultiClickThreshold,但这并没有解决我的问题(你永远不知道声音或音乐文件会有多长)。
有没有人使用过TinySound,或者知道解决这个挑战的方法?
以下是该方法的代码(如有必要,我会提供更多信息):
public void playSound(String filePath) {
soundFile = new File(filePath);
TinySound.init();
Music sound = TinySound.loadMusic(soundFile);
sound.play(false);
while(sound.done()) {
TinySound.shutdown();
}
}
答案 0 :(得分:2)
考虑使用SwingWorker,在按下按钮时禁用JButton,并在SwingWorker完成其操作时重新启用它。重新启用可以在已添加到Swingworker并响应PropertyChangeEvent.newValue()
SwingWorker.StateValue.DONE
的PropertyChangeListener中完成。
例如,您的代码看起来像......,
public class SwingworkerEg {
// .....
public void playSound(String filePath) {
soundFile = new File(filePath);
TinySound.init();
Music sound = TinySound.loadMusic(soundFile);
sound.play(false);
while (sound.done()) {
TinySound.shutdown();
}
}
// The JButton or menu item's Action or ActionListener class
private class PlayAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
// disable the button or menu item
setEnabled(false);
// create worker to play music in a background thread
// pass in the file path
PlayWorker playWorker = new PlayWorker(filePath);
// listen for when the worker thread is done
playWorker.addPropertyChangeListener(new PlayWorkerListener(this));
// execute the worker (in a background thread)
playWorker.execute();
}
}
// To listen for when the worker is done
class PlayWorkerListener implements PropertyChangeListener {
private PlayAction playAction;
// pass in the Action so we can re-enable it when done
public PlayWorkerListener(PlayAction playAction) {
this.playAction = playAction;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is done
if (evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
// re-enable the button
playAction.setEnabled(true);
}
}
}
// this is to call playSound in a background thread
class PlayWorker extends SwingWorker<Void, Void> {
private String filePath;
// pass in the file path String
public PlayWorker(String filePath) {
this.filePath = filePath;
}
@Override
protected Void doInBackground() throws Exception {
// this is called in a background thread
playSound(filePath);
return null;
}
}
}
这是一个微不足道的工作示例:
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
@SuppressWarnings("serial")
public class SwingWorkerEg2 extends JPanel {
private JSpinner spinner = new JSpinner(new SpinnerNumberModel(3, 3, 10, 1));
public SwingWorkerEg2() {
add(new JLabel("Seconds to wait:"));
add(spinner);
add(new JButton(new FooAction("Please Press Me!")));
}
// The JButton or menu item's Action or ActionListener class
private class FooAction extends AbstractAction {
public FooAction(String name) {
super(name); // set button name
int mnemonic = (int) name.charAt(0); // get first letter as int
putValue(MNEMONIC_KEY, mnemonic); // set button mnemonic for first letter
}
@Override
public void actionPerformed(ActionEvent e) {
// disable the button or menu item
setEnabled(false);
int spinnerValue = ((Integer) spinner.getValue()).intValue();
// create worker to play music in a background thread
FooWorker playWorker = new FooWorker(spinnerValue);
// listen for when the worker thread is done
playWorker.addPropertyChangeListener(new FooWorkerListener(this));
// execute the worker (in a background thread)
playWorker.execute();
}
}
// To listen for when the worker is done
class FooWorkerListener implements PropertyChangeListener {
private FooAction fooAction;
// pass in the Action so we can re-enable it when done
public FooWorkerListener(FooAction fooAction) {
this.fooAction = fooAction;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is done
if (evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
// re-enable the button
fooAction.setEnabled(true);
}
}
}
// this is to call count down in a background thread
class FooWorker extends SwingWorker<Void, Void> {
private int spinnerValue;
// pass in the file path String
public FooWorker(int spinnerValue) {
this.spinnerValue = spinnerValue;
}
@Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < spinnerValue; i++) {
System.out.println("count is: " + i);
Thread.sleep(1000);
}
System.out.println("count is: " + spinnerValue);
return null;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SwingWorker Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SwingWorkerEg2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
请务必阅读Concurrency in Swing,详细了解如何使用SwingWorkers
答案 1 :(得分:0)
搞定了!非常感谢你!我将尝试在我的ActionController类中实现它,在SoundHandler中将所有内容保存在同一个方法中有点混乱;)
这是最终正在运行的SoundHandler:
import java.io.File;
import javax.swing.SwingWorker;
import kuusisto.tinysound.Music;
import kuusisto.tinysound.TinySound;
import imports.ActionController;
import imports.GUI;
/**
* This class handles the playing of the sound and extends SwingWorker so that
* the JFrame do not freeze when the sound is played.
*
* @author Gaute Gjerlow Remen
* @version 1.0
*/
public class SoundHandler extends SwingWorker<Void, Void> {
private GUI gui;
private ActionController actionController;
private File soundFile;
public SoundHandler() {
actionController = new ActionController(this);
gui = new GUI(actionController);
}
/**
* Plays the sound file in another thread
* @param filePath
* @throws Exception if the thread is interrupted
* @return null when doInBackground is finished
*/
public void playSound(String filePath) {
soundFile = new File(filePath);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
TinySound.init();
Music sound = TinySound.loadMusic(soundFile);
sound.play(false);
while (!sound.done()) {
gui.unablePlayButton();
}
gui.enablePlayButton();
TinySound.shutdown();
return null;
}
};
worker.execute();
}
/**
* @return file opened in the GUI
*/
public String openFile() {
return gui.openFile();
}
/**
* Calls the about window in GUI
*/
public void showAbout() {
gui.showAbout();
}
/**
* Calls the showNoSong window in GUI
*/
public void showNoSong() {
gui.showNoSong();
}
/**
* Calls the changeSongLabel window in GUI
*/
public void changeSongLabel() {
gui.changeSongLabel();
}
/**
* A empty method made only for the extending of the class
*/
@Override
protected Void doInBackground() throws Exception {
// TODO Auto-generated method stub
return null;
}
}