Java 停止声音按钮无法正常工作
Java Stop Sound Button Not Working Correctly
所以我最近一直在做一个停止按钮,一直想知道如何在播放时立即停止按钮声音。
问题:当你点击停止声音按钮时,它只会停止你按下的下一个按钮。
我要实现的目标:当您单击停止声音按钮时,它会停止所有播放的声音。
这是主按钮 class 声音:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
//JButtons Class
public class Buttons extends JButton implements ActionListener{
private int locX = 0;
private int locY = 0;
//Sets the basic features of the buttons and adds an action listener
public Buttons(String title){
super(title);
setBounds(locX,locY,100,100);
setOpaque(true);
setBorderPainted(false);
setBorder(BorderFactory.createLineBorder(Color.WHITE));
addActionListener(this);
}
//Sets the dimentions of the buttons
public void setDimentions(int x, int y){
this.locX = x;
this.locY = y;
setBounds(locX,locY,100,100);
}
//Maps button colors to sting values
static Map<String, Color> colorMap = Map.ofEntries(Map.entry("WHITE", Color.WHITE), Map.entry("GRAY", Color.GRAY), Map.entry( "BLACK", Color.BLACK), Map.entry( "RED", Color.RED), Map.entry( "ORANGE", new Color(255,121,0)), Map.entry( "YELLOW", Color.YELLOW), Map.entry( "GREEN", Color.GREEN), Map.entry( "BLUE", Color.BLUE), Map.entry( "MAGENTA", Color.MAGENTA), Map.entry( "PINK", Color.PINK), Map.entry( "CYAN", Color.CYAN));
//Gets the color from the map and returns it
static Color getColor(String col){
return colorMap.get(col.toUpperCase());
}
//Sets the color of the button and repaints it
public void setColors(String colorBack, String colorFront){
setBackground(getColor(colorBack));
setForeground(getColor(colorFront));
repaint();
}
public String[] listFilesForFolder(final File folder) {
String[] f = new String[25];
int count = 0;
for(int i = 0; i < 25; i++){
f[i] = "";
}
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
if(fileEntry.getName().equals(".DS_Store")){
}else{
f[count] = fileEntry.getName();
count++;
}
}
}
return f;
}
public void playSound(String url, boolean loop, boolean stop){
try{
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Launchpad.class.getResource("soundFiles/" + url));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
if(loop == true){
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
if(stop == true){
stopSound(clip);
}
}
catch(Exception e){
System.out.println("Error");
}
}
public void stopSound(Clip clip){
if(clip.isActive()){
clip.stop();
clip.flush();
clip.close();
}
}
//Event Handler / Action Listener
@Override
public void actionPerformed(ActionEvent e){
if(e.getSource() == this){
String sNum = this.getText();
int num = Integer.parseInt(sNum);
final File folder = new File("/Users/ethanbowles/Desktop/idk/programing/java/Launchpad/soundFiles");
String[] names =listFilesForFolder(folder);
System.out.println(names[num - 1]);
System.out.println(num);
boolean fullStop = StopButton.stop;
playSound(names[num - 1], LoopButton.loop, fullStop);
StopButton.stop = false;
LoopButton.loop = false;
}
}
}
这里是主要的声音停止按钮:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class StopButton extends JButton implements ActionListener{
public static boolean stop = false;
public StopButton(){
super("Stop");
setBounds(10,10,100,50);
addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e){
if(e.getSource() == this){
if(stop == true){
stop = false;
}else{
stop = true;
}
super.repaint();
}
}
}
我认为您需要更改 Clip
的范围。目前它们是局部变量。它们需要是实例变量。然后,将所有符合“停止”条件的 Clip
放入一个集合中。当您想一次停止它们时,您可以遍历该集合。
拥有 Clip
的集合将需要更多的开销。例如,您必须确保在完成后从集合中删除 Clip
。此外,因为遍历集合和 adding/removing 可能会同时发生,所以 CopyOnWriteArrayList 之类的线程安全集合可能是比 ArrayList
.
更好的选择。
问题是由于一个 JButton 中的 .stop 字段被另一个 JButton 修改的逻辑。重用 playSound() 来播放或停止也不是一个好的设计。
这是一个设计更简洁的解决方案,带有 2 个按钮,一个用于播放,一个用于停止。
MusicController 独立于 UI:
class MusicController
{
// A property for the state of the controller
public final static String PROP_STATE = "StateProperty";
enum State
{
NOT_READY, STOPPED, PLAYING
};
State state = State.NOT_READY;
boolean loop;
// Manage property change listeners
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void loadSound()
{
// Initialize music data, load clip from file etc.
...
State oldState = state;
state = State.STOPPED; // We can actually play a sound only from the STOPPED state
pcs.firePropertyChange(PROP_STATE, oldState, state);
}
public State getState()
{
return state;
}
public void play()
{
switch (state)
{
case NOT_READY:
// Error "Not ready"
...
break;
case STOPPED:
// Start playback (looped if loop is true)
...
State oldState = state;
state = State.PLAYING;
pcs.firePropertyChange(PROP_STATE, oldState, state); // Notify listeners
break;
case PLAYING:
// Already playing, do nothing
break;
default:
throw new AssertionError(state.name());
}
}
public void stop()
{
// Same code structure than play(), but adapted to stop playback if current state is PLAYING.
...
}
public void addPropertyChangeListener(PropertyChangeListener listener)
{
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener)
{
pcs.removePropertyChangeListener(listener);
}
}
View 管理 UI 并且只监听 MusicController 状态。
class View implements PropertyChangeListener
{
JButton playButton, stopButton;
MusicController controller = new MusicController();
public View()
{
// Listen to music controller state changes
controller.addPropertyChangeListener(this);
// Create UI
Action playAction = new AbstractAction("Play")
{
public void actionPerformed(ActionEvent ae)
{
controller.play();
}
};
playButton = new JButton(playAction);
// Same for stopButton with controller.stop();
...
// Add buttons to UI etc.
...
updateUI(controller.getState());
}
/**
* Update the user interface depending on the music controller state.
*
* @param state
*/
private void updateUI(State state)
{
switch (state)
{
case NOT_READY:
playButton.setEnabled(false);
stopButton.setEnabled(false);
break;
case STOPPED:
playButton.setEnabled(true);
stopButton.setEnabled(false);
break;
case PLAYING:
playButton.setEnabled(false);
stopButton.setEnabled(true);
break;
default:
throw new AssertionError(state.name());
}
}
/**
* Called when a MusicController property has changed.
*/
public void propertyChange(PropertyChangeEvent evt)
{
if (evt.getSource() == controller && MusicController.PROP_STATE.equals(evt.getPropertyName()))
{
// State has changed, update UI accordingly
State state = (State) evt.getNewValue();
updateUI(state);
}
}
}
所以我最近一直在做一个停止按钮,一直想知道如何在播放时立即停止按钮声音。
问题:当你点击停止声音按钮时,它只会停止你按下的下一个按钮。
我要实现的目标:当您单击停止声音按钮时,它会停止所有播放的声音。
这是主按钮 class 声音:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
//JButtons Class
public class Buttons extends JButton implements ActionListener{
private int locX = 0;
private int locY = 0;
//Sets the basic features of the buttons and adds an action listener
public Buttons(String title){
super(title);
setBounds(locX,locY,100,100);
setOpaque(true);
setBorderPainted(false);
setBorder(BorderFactory.createLineBorder(Color.WHITE));
addActionListener(this);
}
//Sets the dimentions of the buttons
public void setDimentions(int x, int y){
this.locX = x;
this.locY = y;
setBounds(locX,locY,100,100);
}
//Maps button colors to sting values
static Map<String, Color> colorMap = Map.ofEntries(Map.entry("WHITE", Color.WHITE), Map.entry("GRAY", Color.GRAY), Map.entry( "BLACK", Color.BLACK), Map.entry( "RED", Color.RED), Map.entry( "ORANGE", new Color(255,121,0)), Map.entry( "YELLOW", Color.YELLOW), Map.entry( "GREEN", Color.GREEN), Map.entry( "BLUE", Color.BLUE), Map.entry( "MAGENTA", Color.MAGENTA), Map.entry( "PINK", Color.PINK), Map.entry( "CYAN", Color.CYAN));
//Gets the color from the map and returns it
static Color getColor(String col){
return colorMap.get(col.toUpperCase());
}
//Sets the color of the button and repaints it
public void setColors(String colorBack, String colorFront){
setBackground(getColor(colorBack));
setForeground(getColor(colorFront));
repaint();
}
public String[] listFilesForFolder(final File folder) {
String[] f = new String[25];
int count = 0;
for(int i = 0; i < 25; i++){
f[i] = "";
}
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
if(fileEntry.getName().equals(".DS_Store")){
}else{
f[count] = fileEntry.getName();
count++;
}
}
}
return f;
}
public void playSound(String url, boolean loop, boolean stop){
try{
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Launchpad.class.getResource("soundFiles/" + url));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
if(loop == true){
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
if(stop == true){
stopSound(clip);
}
}
catch(Exception e){
System.out.println("Error");
}
}
public void stopSound(Clip clip){
if(clip.isActive()){
clip.stop();
clip.flush();
clip.close();
}
}
//Event Handler / Action Listener
@Override
public void actionPerformed(ActionEvent e){
if(e.getSource() == this){
String sNum = this.getText();
int num = Integer.parseInt(sNum);
final File folder = new File("/Users/ethanbowles/Desktop/idk/programing/java/Launchpad/soundFiles");
String[] names =listFilesForFolder(folder);
System.out.println(names[num - 1]);
System.out.println(num);
boolean fullStop = StopButton.stop;
playSound(names[num - 1], LoopButton.loop, fullStop);
StopButton.stop = false;
LoopButton.loop = false;
}
}
}
这里是主要的声音停止按钮:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class StopButton extends JButton implements ActionListener{
public static boolean stop = false;
public StopButton(){
super("Stop");
setBounds(10,10,100,50);
addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e){
if(e.getSource() == this){
if(stop == true){
stop = false;
}else{
stop = true;
}
super.repaint();
}
}
}
我认为您需要更改 Clip
的范围。目前它们是局部变量。它们需要是实例变量。然后,将所有符合“停止”条件的 Clip
放入一个集合中。当您想一次停止它们时,您可以遍历该集合。
拥有 Clip
的集合将需要更多的开销。例如,您必须确保在完成后从集合中删除 Clip
。此外,因为遍历集合和 adding/removing 可能会同时发生,所以 CopyOnWriteArrayList 之类的线程安全集合可能是比 ArrayList
.
问题是由于一个 JButton 中的 .stop 字段被另一个 JButton 修改的逻辑。重用 playSound() 来播放或停止也不是一个好的设计。
这是一个设计更简洁的解决方案,带有 2 个按钮,一个用于播放,一个用于停止。
MusicController 独立于 UI:
class MusicController
{
// A property for the state of the controller
public final static String PROP_STATE = "StateProperty";
enum State
{
NOT_READY, STOPPED, PLAYING
};
State state = State.NOT_READY;
boolean loop;
// Manage property change listeners
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void loadSound()
{
// Initialize music data, load clip from file etc.
...
State oldState = state;
state = State.STOPPED; // We can actually play a sound only from the STOPPED state
pcs.firePropertyChange(PROP_STATE, oldState, state);
}
public State getState()
{
return state;
}
public void play()
{
switch (state)
{
case NOT_READY:
// Error "Not ready"
...
break;
case STOPPED:
// Start playback (looped if loop is true)
...
State oldState = state;
state = State.PLAYING;
pcs.firePropertyChange(PROP_STATE, oldState, state); // Notify listeners
break;
case PLAYING:
// Already playing, do nothing
break;
default:
throw new AssertionError(state.name());
}
}
public void stop()
{
// Same code structure than play(), but adapted to stop playback if current state is PLAYING.
...
}
public void addPropertyChangeListener(PropertyChangeListener listener)
{
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener)
{
pcs.removePropertyChangeListener(listener);
}
}
View 管理 UI 并且只监听 MusicController 状态。
class View implements PropertyChangeListener
{
JButton playButton, stopButton;
MusicController controller = new MusicController();
public View()
{
// Listen to music controller state changes
controller.addPropertyChangeListener(this);
// Create UI
Action playAction = new AbstractAction("Play")
{
public void actionPerformed(ActionEvent ae)
{
controller.play();
}
};
playButton = new JButton(playAction);
// Same for stopButton with controller.stop();
...
// Add buttons to UI etc.
...
updateUI(controller.getState());
}
/**
* Update the user interface depending on the music controller state.
*
* @param state
*/
private void updateUI(State state)
{
switch (state)
{
case NOT_READY:
playButton.setEnabled(false);
stopButton.setEnabled(false);
break;
case STOPPED:
playButton.setEnabled(true);
stopButton.setEnabled(false);
break;
case PLAYING:
playButton.setEnabled(false);
stopButton.setEnabled(true);
break;
default:
throw new AssertionError(state.name());
}
}
/**
* Called when a MusicController property has changed.
*/
public void propertyChange(PropertyChangeEvent evt)
{
if (evt.getSource() == controller && MusicController.PROP_STATE.equals(evt.getPropertyName()))
{
// State has changed, update UI accordingly
State state = (State) evt.getNewValue();
updateUI(state);
}
}
}