问题描述
所以我最近一直在制作一个停止按钮,并且一直想知道如何在已经播放时立即停止按钮声音。
问题:当您单击停止声音按钮时,它只会停止您按下的下一个按钮。
我想要实现的目标:当您单击停止声音按钮时,它会停止所有播放的声音。
这是主要的按钮类声音:
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,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,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
。此外,由于遍历集合和添加/删除可能同时发生,因此线程安全集合(例如 CopyOnWriteArrayList)可能比 ArrayList
更好。
问题是由于一个 JButton 中的 .stop 字段被另一个 JButton 修改的逻辑。重用 playSound() 来播放或停止也不是一个好的设计。
这是一种设计更简洁的解决方案,带有 2 个按钮,一个用于播放,一个用于停止。
MusicController 独立于 UI:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Database Project</title>
<script src="https://kit.fontawesome.com/d6307e6979.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h2>Sales</h2>
<div class="select-box">
<div class="options-container">
</div>
<div class="selected">
<p>Select Item</p>
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
View 管理 UI,只监听 MusicController 状态。
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,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);
}
}