gpt4 book ai didi

java - Java 中的操作停止工作

转载 作者:行者123 更新时间:2023-12-02 03:03:06 25 4
gpt4 key购买 nike

所以这是我的第一篇文章,如果我的语法不好(英语不是我的母语),我真的很抱歉。我最近开始用java编程,我有兴趣学习。因此,我开始了一些小项目来帮助我了解更多基本内容并改进我的编码。

最近我读到了有关 keyListeners、keyBindings 和所有这些内容的内容。所以我想我编写了一个非常基本的程序(几乎没有图形用户界面),它应该像一个简单的钢琴一样工作:

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import java.awt.*;
import java.io.File;
import javax.swing.*;

import java.awt.event.*;

public class pianl1 {


public static void main (String[] args){
int i= 0;

File C7 = new File("res/39191__jobro__piano-ff-044.wav");
File D7 = new File ("res/39194__jobro__piano-ff-046.wav");

JLabel lab1 =new JLabel("Hallo");
frame.add(lab1);


AbstractAction keyBindingReactorC7 = new AbstractAction(){
@Override
public void actionPerformed(ActionEvent e){
Playsound(C7);
}
};
AbstractAction keyBindingReactorD7 = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
Playsound(D7);
}

JPanel panel= new JPanel(new FlowLayout());
frame.getContentPane().add(panel);
frame.pack();

panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("C"),
"cPressed");
panel.getActionMap().put("cPressed", keyBindingReactorC7);

panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"),
"dPressed");
panel.getActionMap().put("dPressed", keyBindingReactorD7);


public static void Playsound(File Sound){
try{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(Sound));
clip.start();

}catch(Exception e){}

}

}

并且运行良好。如果我按下琴键,它就会播放声音,即使我敲击琴键,声音也几乎没有延迟。这正是我想要的。

但是有一个小错误。

如果我一直按一个键,或者同时按两个键(这有效,它会同时播放两个键),有时会发生根本没有声音的情况。我无能为力让它再次工作,我所能做的就是重新启动整个程序。这种情况是随机发生的,我不明白为什么。我知道有什么东西阻碍了我的行动持续进行。

最佳答案

你的问题的答案围绕着你最终想要实现的目标,如果你只是想停止多个声音的播放,那么你需要某种可以监控的条件,如果你想停止“特定”的声音从玩,那么你需要保持某种List您可以检查的标志。

因此,根据您的代码,假设您正在制作一架钢琴,因此您希望声音重叠,在这种情况下,我们需要某种方法来确定是否播放了特定的声音。

有很多方法可以实现这一目标,但我们选择 Set ,这使您可以保持唯一的 List项目(无重复)。

每次playSound被调用时,我们检查这个列表并确定声音是否已经播放过,如果没有,我们将声音添加到列表中并播放它,当声音停止时,我们将其从列表中删除

核心...

我对你的代码做了一些更改,稍后我将详细解释它,但本质上,这是这个想法的“核心”......

private Set<File> playing = new HashSet<File>(25);

public void playsound(File sound) {
try {
// Is the been played or not?
if (!playing.contains(sound)) {
// And the sound to prevent it from been played again
playing.add(sound);
// Set up a new clip
Clip clip = AudioSystem.getClip();
// Monitor the clip's status, we want to know when it ends
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
// Clip has stopped
if (event.getType() == LineEvent.Type.STOP) {
// Release the resources
clip.close();
// Remove the sound from our list
// so it can be played again
playing.remove(sound);
}
}
});
// Play it again Sam
clip.open(AudioSystem.getAudioInputStream(sound));
clip.start();
}
} catch (Exception e) {
// Remove the sound if something goes wrong
playing.remove(sound);
e.printStackTrace();
}

}

可运行示例

好吧,我已经“更新”了你的代码一点,原因如下......

  • Java 有一些既定的编码约定,鼓励所有开发人员遵循,它们使其他人更容易阅读您的代码,也让您更轻松地阅读他们的代码,请查看 Code Conventions for the Java TM Programming Language更多细节。话虽如此,我让所有变量都以小写字符开头
  • A 创建了一个自定义面板。好吧,这只是我的想法,但这让生活变得更轻松,因为您可以更轻松地封装您要实现的逻辑。因为您正在使用 Action API,另一种选择是创建一个 SoundManager类,其中包含管理和播放声音的逻辑,并传递对每个 Action 的引用。就我个人而言,我最终可能会两者兼而有之
  • 我用过EventQueue.invokeLater确保 UI 是在事件调度线程的上下文中创建的,从而减少违反 Swing 单线程性质的任何可能的风险,这始终是一个好主意;)

你似乎在尝试事情上有了一个良好的开端,干得好,继续努力!

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

public static void main(String[] args) {
new Test();
}

public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

public TestPane() {

File c7 = new File("res/res39191__jobro__piano-ff-044.wav");
File d7 = new File("res/39194__jobro__piano-ff-046.wav");

add(new JLabel("Hello"));

AbstractAction keyBindingReactorC7 = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
playsound(c7);
}
};
AbstractAction keyBindingReactorD7 = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
playsound(d7);
}
};
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("C"),
"cPressed");
getActionMap().put("cPressed", keyBindingReactorC7);

getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"),
"dPressed");
getActionMap().put("dPressed", keyBindingReactorD7);
}

private Set<File> playing = new HashSet<File>(25);

public void playsound(File sound) {
try {
if (!playing.contains(sound)) {
playing.add(sound);
Clip clip = AudioSystem.getClip();
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
clip.close();
playing.remove(sound);
}
}
});
clip.open(AudioSystem.getAudioInputStream(sound));
clip.start();
}
} catch (Exception e) {
playing.remove(sound);
e.printStackTrace();
}

}
}
}

好的,但是我该如何使其一次只能播放一种声音?

啊,好问题...

基本上,我们使用单个剪辑并检查它的状态...

private Clip clip;

public void playsound(File sound) {
try {
if (clip == null) {
clip = AudioSystem.getClip();
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
clip.close();
}
}
});
}
// Is the clip active or running?
if (!clip.isActive() && !clip.isRunning()) {
if (clip.isOpen()) {
clip.close();
}
clip.open(AudioSystem.getAudioInputStream(sound));
clip.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}

现在,我对 Java 的音频体验几乎不存在,但我可能会考虑尝试一些事情......

  • 创建 AudioManagerSoundManager类,它管理声音并提供一个简单的播放声音的界面(如 playCplayD )。预加载每个声音的剪辑。这将需要一些额外的管理,因为当剪辑结束时,您将需要将其“重置”回开头。这“应该”使播放剪辑的速度更快,但它可能会消耗更多资源,哪种权衡对您来说更重要?您还可以创建某种缓存,如果某个剪辑在一段时间内没有播放,它将被关闭并丢弃。
  • 继续播放声音直到松开按键...对您来说是一个很好的挑战;)

关于java - Java 中的操作停止工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42171398/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com