TinySound和GUI中的多次单击(按钮)

时间:2015-01-21 21:44:56

标签: java audio jbutton

我正在努力解决使用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();
        }
    }

2 个答案:

答案 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;
    }
}