动作在Java中停止工作 [英] Actions stop working in Java

查看:118
本文介绍了动作在Java中停止工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以这是我的第一篇文章,如果语法不好(英语不是我的母语),我真的很抱歉.我最近开始用Java编程,我对学习很感兴趣.因此,我开始了一些小项目,以帮助我了解更多基本知识并改善编码.

so this is my very first post and i am really sorry if my grammar is bad (english is not my mother language). I recently started programming in java and i am interested in learning. So i started a few small projects to help me understand more of the basic stuff and to improve my coding.

最近,我读到了有关keyListeners,keyBindings以及所有这些东西的信息.所以我以为我编写了一个非常基本的程序(几乎没有gui),应该像一架简单的钢琴一样工作:

Recently i read about keyListeners, keyBindings and all that stuff. So i thought i code a very basic program (nearly no gui) which should work like a simple piano:

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){}

    }

}

它运行正常.如果我按这些键,它会播放声音,即使我敲击这些键,声音也几乎没有延迟.这正是我想要的.

And it is working fine. If i press the keys, it plays the sound, and even if i hammer the keys the sound has almost no delay. Which is exactly what i wanted.

但是有一个小错误.

如果我持续按下一个键,或者同时按下两个键(这有效,它将同时播放两个键),有时会发生,根本没有声音.我无法做任何事情来使其再次工作,而我所能做的就是重新启动整个程序.这是随机发生的,我不知道为什么.我知道某些事情阻止了我的行为不断发挥作用.

If i keep pressing one key, or i press two keys at the same time (which works, it plays both at the same time), it sometimes happens, that there will be no sound at all. I can't do anything to get it to work again and all i can do is restart the whole program. This happens randomly and i cant figure out why. I know that something is blocking my actions from working continuously.

推荐答案

问题的答案取决于您最终想要达到的目标,如果您只想停止播放多个声音,那么您需要某种条件您可以监视,如果要停止播放特定"的声音,则需要维护某种List标志,您可以对其进行检查.

The answer to your question revolves around what you ultimately want to achieve, if you simply want to stop more than one sound playing, then you need some kind of condition you can monitor, if you want to stop a "particular" sound from playing, then you need to maintain some kind of List of flags which you can check.

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

So, based on your code, lets assume you're making a piano, so you want sounds to overlap, in this case, we need some way to determine if a particular sound is been played or not.

有多种方法可以实现此目的,但让我们选择Set即可,它使您可以维护唯一的List项(无重复项).

There are a number of ways to achieve this, but lets settle on a Set, which allows you to maintain unique a List of items (no duplicates).

每次调用playSound时,我们都会检查此列表并确定是否已播放声音,如果尚未播放,则将声音添加到列表中并播放,当声音停止时,我们从列表中将其删除

Each time playSound is called, we check this list and determine if the sounds is already been played or not, if it isn't, we add the sound to the list and play it, when the sound stops, we remove it from the list

我对您的代码进行了一些更改,稍后我将对其进行详细说明,但从本质上讲,这是该想法的核心" ...

I've changed your code a bit and I'll explain it more it detail later, but essentially, this is the "core" of the idea...

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();
    }

}

可运行的示例

好的,所以我已经稍微更新"了您的代码,这就是为什么...

Runnable example

Okay, so I've "updated" your code a little, here's why...

  • Java具有一些已建立的编码约定,鼓励所有开发人员都遵循Java,它们使其他人更容易阅读您的代码,而您阅读它们的代码更容易,请参阅
  • Java has some established coding conventions all developers are encouraged to follow, they make it easier for other people to read your code and for you to read theirs, take a look at at Code Conventions for the Java TM Programming Language for more details. Having said, I made all your variables start with a lowercase character
  • A created a custom panel. Okay, this is just me, but it makes life a lot easier as you can more easily encapsulate the logic you are trying to implement. Because you're making use of the Action API, another choice would have been to create a SoundManager class, which contained the logic for managing and playing the sounds and passed a reference to each Action, personally, I'd probably end up with both
  • I've used EventQueue.invokeLater to ensure that the UI is created within the context of the Event Dispatching Thread, reducing any possible risk of violating the single threaded nature of Swing, always a good idea ;)

您似乎已经开始尝试,做好,继续努力了!

You seem to be off to a good start trying things, well done, keep it up!

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();
            }

        }
    }
}

好的,但是我该怎么做,以便一次只能播放一个声音?

啊,好问题...

Ok, but how do I make it so only one sound can play at a time?

Ah, good question...

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

Basically, we use a single clip and check it's state...

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的音频体验,但是有些事情我可能会考虑尝试...

Now, my audio experience with Java is pretty non-existent, but some things I might consider trying...

  • 制作一个AudioManagerSoundManager类,该类管理声音并提供一个简单的界面来播放声音(例如playCplayD).预加载每种声音的片段.这将需要一些额外的管理,因为剪辑结束时,您需要将其重置"回开始.这种应该"使播放剪辑的速度更快,但是它可能会消耗更多的资源,哪种折衷对您来说更重要?您还可以创建某种类型的缓存,如果剪辑在一段时间内没有播放,则会将其关闭并丢弃.
  • 继续播放声音,直到释放琴键...对您来说是个不错的挑战;)
  • Make a AudioManager or SoundManager class, which manages the sounds and provides a simple interface for playing them (like playC, playD). Pre-load the clips for each sound. This is going to require some additional management, because when the clip ends, you will need to "reset" it back to the start. This "should" make it faster to play the clips, but it will probably consume more resources, which trade off is more important to you? You could also create some kind of cache, where if a clip isn't played for a period of time, it's closed and disposed of.
  • Keep playing a sound till a key is released...nice challenge for you ;)

这篇关于动作在Java中停止工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆