面板无法与Java Swing中的声音文件同时显示 [英] Panel Fails to Show Up Concurrently with Sound File In Java Swing

查看:104
本文介绍了面板无法与Java Swing中的声音文件同时显示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的游戏对话框结束后,一个可怕的弹出窗口似乎会发出刺耳的声音.当我单击按钮(BPanel)时,图片显示为损坏",直到声音文件播放完毕.尖叫结束后,图片弹出.

是否可以将两者简单地同步在一起? 请注意,该问题发生在使用Scaryface.png和Sound类的Woc类中.

主要方法:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Game {
    public static void main(String args[]) {
        Woc WineOrCheese = new Woc("Wine or Cheese");
        WineOrCheese.applyBackground("TitleBackground.png");
        WineOrCheese.applyButton("Play.png", 250, 200, 400, 200);
    }
}

Woc是JFrame

import static java.lang.System.out;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class Woc extends JFrame {

private JFrame window;
private Woc.BPanel background;

private BufferedImage backgroundImg;
final int HEIGHT = 600;
final int WIDTH = 900;
private BufferedImage scaryImg;

public Woc(String text) {
    /*********************************
     * Sets up window. *
     ********************************/
    window = new JFrame(text);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setLayout(null);

    window.setVisible(true);
    window.setSize(WIDTH, HEIGHT);
    window.setLocationRelativeTo(null);
}

public void applyBackground(String ImgName) {
    try {
        backgroundImg = ImageIO.read(getClass().getResource(ImgName));
    } catch (IOException e) {
        out.println("No image detected");
    }

    background = new Woc.BPanel(backgroundImg, 0, 0, WIDTH, HEIGHT);

    window.add(background);
    background.setBounds(0, 0, WIDTH, HEIGHT);
}

public void applyButton(String ImgName, int x1, int y1, int width,
        int height) {
    BufferedImage buttonImg = null;
    try {
        buttonImg = ImageIO.read(getClass().getResource(ImgName));
    } catch (IOException e) {
    }

    Woc.BPanel button = new Woc.BPanel(buttonImg, x1, y1, width, height);

    window.add(button);
    button.setBounds(0, 0, WIDTH, HEIGHT);
    button.addMouseListener(new Clicker());

}

public static void play(String filename) {
    try {
        Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(new File(filename)));
        clip.start();
    } catch (Exception exc) {
        exc.printStackTrace(System.out);
    }
}

private class BPanel extends JPanel {
    public BufferedImage img;
    public int x1, y1, width, height;

    public BPanel(BufferedImage img, int x1, int y1, int width, int height) {
        super();
        this.img = img;
        this.x1 = x1;
        this.y1 = y1;
        this.width = width;
        this.height = height;
        // this.setOpaque(false);
        this.setBackground(new Color(0, 0, 0, 0));
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, x1, y1, width, height, null);
    }
}

private class Clicker implements MouseListener {

    @Override
    public void mouseClicked(MouseEvent arg0) {

        //Dialog of game is here in the form of JOptionPane.

        applyBackground("Scaryface.png");
        for (int k = 0; k < 10; k++) {
            for (int z = 0; z < 10; z++) {
                out.println(".");
            }
        }

        Sound scary = null;
        try {
            scary = new Sound("scary.wav", window);
        } catch (Exception e) {
        }

    }

    @Override
    public void mouseEntered(MouseEvent arg0) {

    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

}

声音类:

import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.*;

public class Sound {

    public Sound(String s, JFrame win) throws InterruptedException {
        Clip play = null;
        try {
            File in = new File(s);
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(in);
            play = AudioSystem.getClip();
            play.open(audioInputStream);
            FloatControl volume = (FloatControl) play.getControl(FloatControl.Type.MASTER_GAIN);
            volume.setValue(1.0f); // Reduce volume by 10 decibels.
            play.start();
            // Loop until the Clip is not longer running.
            // We loop this way to allow the line to fill, otherwise isRunning will
            // return false
            do {
                Thread.sleep(10);
            } while (play.isRunning());
            play.drain();
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
            ex.printStackTrace();
        } finally {
            try {
                play.close();
            } catch (Exception exp) {
            }
        }
    }
}

顺便说一下,有什么技巧可以使我的游戏更容易编写?有什么方法或类可以改善和减轻我必须经历的痛苦吗? (好的,不是真正的痛苦,但仍然很痛苦)

解决方案

do { 
    Thread.sleep(10); 
} while (play.isRunning());

play.drain();

正在使用上述代码阻止事件分发线程,从而阻止了UI的更新.有关更多详细信息,请参见 Swing中的并发

避免使用null布局,像素完美布局是现代ui设计中的一种幻觉.有太多因素会影响组件的单个大小,您无法控制. Swing旨在与布局管理者为核心一起工作,舍弃这些问题不会导致任何问题,而您将花费越来越多的时间进行纠正

您不应该在按钮上使用MouseListener,而是在ActionListener上触发按钮.请参见如何使用按钮,复选框和单选按钮如何编写动作监听器以获取更多详细信息

如果您想知道音频何时结束,则应该使用LineListener

对于更复杂的示例,使用Swing和Clip,请查看

Is it possible to simply synchronize the two together? Note that the problem is happening in the Woc class where Scaryface.png and the Sound class is used.

Main method:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Game {
    public static void main(String args[]) {
        Woc WineOrCheese = new Woc("Wine or Cheese");
        WineOrCheese.applyBackground("TitleBackground.png");
        WineOrCheese.applyButton("Play.png", 250, 200, 400, 200);
    }
}

Woc is the JFrame

import static java.lang.System.out;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class Woc extends JFrame {

private JFrame window;
private Woc.BPanel background;

private BufferedImage backgroundImg;
final int HEIGHT = 600;
final int WIDTH = 900;
private BufferedImage scaryImg;

public Woc(String text) {
    /*********************************
     * Sets up window. *
     ********************************/
    window = new JFrame(text);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setLayout(null);

    window.setVisible(true);
    window.setSize(WIDTH, HEIGHT);
    window.setLocationRelativeTo(null);
}

public void applyBackground(String ImgName) {
    try {
        backgroundImg = ImageIO.read(getClass().getResource(ImgName));
    } catch (IOException e) {
        out.println("No image detected");
    }

    background = new Woc.BPanel(backgroundImg, 0, 0, WIDTH, HEIGHT);

    window.add(background);
    background.setBounds(0, 0, WIDTH, HEIGHT);
}

public void applyButton(String ImgName, int x1, int y1, int width,
        int height) {
    BufferedImage buttonImg = null;
    try {
        buttonImg = ImageIO.read(getClass().getResource(ImgName));
    } catch (IOException e) {
    }

    Woc.BPanel button = new Woc.BPanel(buttonImg, x1, y1, width, height);

    window.add(button);
    button.setBounds(0, 0, WIDTH, HEIGHT);
    button.addMouseListener(new Clicker());

}

public static void play(String filename) {
    try {
        Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(new File(filename)));
        clip.start();
    } catch (Exception exc) {
        exc.printStackTrace(System.out);
    }
}

private class BPanel extends JPanel {
    public BufferedImage img;
    public int x1, y1, width, height;

    public BPanel(BufferedImage img, int x1, int y1, int width, int height) {
        super();
        this.img = img;
        this.x1 = x1;
        this.y1 = y1;
        this.width = width;
        this.height = height;
        // this.setOpaque(false);
        this.setBackground(new Color(0, 0, 0, 0));
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, x1, y1, width, height, null);
    }
}

private class Clicker implements MouseListener {

    @Override
    public void mouseClicked(MouseEvent arg0) {

        //Dialog of game is here in the form of JOptionPane.

        applyBackground("Scaryface.png");
        for (int k = 0; k < 10; k++) {
            for (int z = 0; z < 10; z++) {
                out.println(".");
            }
        }

        Sound scary = null;
        try {
            scary = new Sound("scary.wav", window);
        } catch (Exception e) {
        }

    }

    @Override
    public void mouseEntered(MouseEvent arg0) {

    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

}

Sound class:

import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.*;

public class Sound {

    public Sound(String s, JFrame win) throws InterruptedException {
        Clip play = null;
        try {
            File in = new File(s);
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(in);
            play = AudioSystem.getClip();
            play.open(audioInputStream);
            FloatControl volume = (FloatControl) play.getControl(FloatControl.Type.MASTER_GAIN);
            volume.setValue(1.0f); // Reduce volume by 10 decibels.
            play.start();
            // Loop until the Clip is not longer running.
            // We loop this way to allow the line to fill, otherwise isRunning will
            // return false
            do {
                Thread.sleep(10);
            } while (play.isRunning());
            play.drain();
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
            ex.printStackTrace();
        } finally {
            try {
                play.close();
            } catch (Exception exp) {
            }
        }
    }
}

By the way, are there any tips of how to make my game much easier to write? Any methods or classes that can improve and ease the pain I have to go through to? (Okay fine not real pain but it's still painful)

解决方案

do { 
    Thread.sleep(10); 
} while (play.isRunning());

and

play.drain();

Are blocking the Event Dispatching Thread with the aforementioned code which is preventing the UI from been updated. See Concurrency in Swing for more details

Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify

You shouldn't be using a MouseListener with buttons, but instead a ActionListener, there is more then one way to trigger a button. See How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listeners for more details

If you want to know when the audio has finished, you should be using a LineListener, for example. With this, you can choose what to do when the audio has completed. Personally, I would pass the an instance of LineListener to your Sound class, as your Sound class shouldn't care about anything other then playing the sound

Without the while loop, the sound is unable to play. How do I resolve this issue because this was the only way I was able to play the sound

Don't close the Clip until after the audio has completed, for this I would use (another) LineListener.

The following example basically takes your Sound class and applies a LineListener to it. One is used to notified the interested party (the one who started the sound) about line events and one is used to monitor the clip internally and close it when it stops.

The example use a ReentrantLock and Condition to stop the code execution until the clip has completed, in this example, this will stop the JVM from terminating, but you don't need, I just used to provide a basic demonstration

import java.io.File;
import java.io.IOException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

public class TestAudio {

    public static void main(String[] args) {
        ReentrantLock lockWait = new ReentrantLock();
        Condition conWait = lockWait.newCondition();
        try {
            new Sound("...", new LineListener() {
                @Override
                public void update(LineEvent event) {
                    if (event.getType().equals(LineEvent.Type.STOP)) {
                        System.out.println("Line has stopped");
                        lockWait.lock();
                        try {
                            conWait.signal();
                        } finally {
                            lockWait.unlock();
                        }
                    }
                }
            });
            System.out.println("Waiting for audio to finish");
            lockWait.lock();
            try {
                conWait.await();
            } finally {
                lockWait.unlock();
            }
            System.out.println("Audio has finished");
        } catch (InterruptedException | LineUnavailableException | IOException | UnsupportedAudioFileException exp) {
            exp.printStackTrace();
        }
    }

    public static class Sound {

        private Clip play;

        public Sound(String s, LineListener listener) throws InterruptedException, LineUnavailableException, IOException, UnsupportedAudioFileException {
            play = null;
            File in = new File(s);
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(in);
            play = AudioSystem.getClip();
            play.addLineListener(new LineListener() {
                @Override
                public void update(LineEvent event) {
                    if (event.getType().equals(LineEvent.Type.STOP)) {
                        System.out.println("Audio stopped, closing clip");
                        play.close();
                    }
                }
            });
            play.addLineListener(listener);
            play.open(audioInputStream);
            FloatControl volume = (FloatControl) play.getControl(FloatControl.Type.MASTER_GAIN);
            volume.setValue(1.0f); // Reduce volume by 10 decibels.
            play.start();
        }
    }

}

For a more complex example, using Swing and Clip, have a look at Playing multiple sound clips using Clip objects

这篇关于面板无法与Java Swing中的声音文件同时显示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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