Java 实验- Swing 音乐播放器

实验要求:

综合利用Swing界面和自己写音乐播放类,设计音乐播放器如下:

(1)纯Swing给定的组件可以设计出一个普通的音乐播放器界面。如果有PS功底或者想追求界面的绚丽,素材可以自己设计也可以通过自己渠道寻求美工帮助。主要是按钮,进度条,标签等显示效果。

(2)音乐播放方面,不能调用其他第三方jar包,只能用JDK底层自带的API类,例如JavaSound。使用JavaSound API,可以实现各种基于声音的应用,例如声音录制、音乐播放、网络电话、音乐编辑等。JavaSound API又以各种解码和合成器SPI(服务提供者接口, Service Provider Interface)为基础,实现各种音乐格式的解码与转码。

说明:

纯属是为了应付实验要求,写了一坨屎山代码,如果有需要的可以去应付一下hh

代码:

音乐播放器MusicPlayer类:

package com.junlin.exer10;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @Description:
 * @author: junlin623
 * @create: 2022-11-25 17:20
 */
public class MusicPlayer {
    private File file;  //音频的路径
    // 是否循环播放
    private volatile boolean isLoop = false;
    // 是否正在播放
    private volatile boolean isPlaying = false;
    float newVolumn = 7;  //音量

    private PlayThread playThread;   //音乐播放线程
    private MusicPlayer musicPlayer = this;
    private MyFrame host;  //依附的主界面


    public MusicPlayer(MyFrame host, File file) {
        this.host = host;
        this.file = file;
        if(!this.file.exists()) {
            System.out.println("文件不存在");
            System.exit(0);
        }
    }

    /**
     * 播放音乐
     */
    public void play() {
        //新建一个播放音乐的线程
        if(playThread != null) playThread.stop();  //当点击开始会从头开始播放音乐
        playThread = new PlayThread();
        playThread.start();

    }

    /**
     * 结束音乐(并非暂停)
     */
    public void over() {
        isPlaying = false;
        if (playThread != null) {
            playThread = null;
        }
    }

    /**
     * 设置循环播放
     * @param isLoop
     * @return 返回当前对象
     */
    public MusicPlayer setLoop(boolean isLoop) {
        this.isLoop = isLoop;
        return this;
    }

    /**
     * -80.0~6.0206测试,越小音量越小
     * @param newVolumn
     * @return 返回当前对象
     */
    public MusicPlayer setVolumn(float newVolumn) {
        this.newVolumn = newVolumn;
        return this;
    }

    /**
     * 设置是否进行播放
     * @param playing
     */
    public void setPlaying(boolean playing) {
        isPlaying = playing;
    }

    // 暂停播放音频
    public void stopMusic() {
        synchronized (this) {
            isPlaying = false;
            notifyAll();
        }
    }

    // 继续播放音乐
    public void continueMusic() {
        synchronized (this) {
            isPlaying = true;
            notifyAll();
        }
    }


    /**
     * 异步播放线程
     */
    private class PlayThread extends Thread {

        @Override
        public void run() {
            isPlaying = true;
            while(true) {
                SourceDataLine sourceDataLine = null;
                BufferedInputStream bufIn = null;
                AudioInputStream audioIn = null;
                try {
                    bufIn = new BufferedInputStream(new FileInputStream(file));
                    audioIn = AudioSystem.getAudioInputStream(bufIn); // 可直接传入file
                    AudioFormat format = audioIn.getFormat();
                    sourceDataLine = AudioSystem.getSourceDataLine(format);
                    sourceDataLine.open();
                    // 必须open之后
                    sourceDataLine.start();
                    byte[] buf = new byte[512];
//             System.out.println(audioIn.available());
                    int len = -1;
                    int cnt = 0;
                    while ((len = audioIn.read(buf)) != -1) {
                        synchronized (musicPlayer) {
                            while(!isPlaying) {   //如果停止播放了就让该线程等待
                                musicPlayer.wait();
                            }
                            if (newVolumn != 7) {
                                FloatControl control = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);
                                //调节音量
                                System.out.println("当前音量:" + newVolumn);
                                control.setValue(newVolumn);
                            }
                        }
                        cnt += len;
                        System.out.println("now: " + cnt);
                        System.out.println((1.0*cnt) / host.length);
                        host.progressBar.setString("" + (int)((1.0*cnt) / host.length * 100) + "%");
                        host.progressBar.setValue(cnt);
                        host.progressBar.paintImmediately(host.progressBar.getBounds());
                        sourceDataLine.write(buf, 0, len);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (sourceDataLine != null) {
                        sourceDataLine.drain();
                        sourceDataLine.close();
                    }
                    try {
                        if (bufIn != null) {
                            bufIn.close();
                        }
                        if (audioIn != null) {
                            audioIn.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }
}

鼠标事件监听类ButtonHandler类:

package com.junlin.exer10;

import javax.swing.JButton;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * @Description:
 * @author: junlin623
 * @create: 2022-11-27 14:15
 */
public class ButtonHandler implements ActionListener {
    private MyFrame window;
    private MusicPlayer musicPlayer;
    public ButtonHandler(MyFrame window, MusicPlayer musicPlayer) {
        this.window = window;
        this.musicPlayer = musicPlayer;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JButton sourceBtn = (JButton) e.getSource();
        if(sourceBtn == this.window.playBtn) {
            //开始播放
//            this.musicPlayer.startMusic();
            this.musicPlayer.play();
        }else if(sourceBtn == this.window.stopBtn) {
            //暂停
            this.musicPlayer.stopMusic();
        }else {
            //继续播放
            this.musicPlayer.continueMusic();
        }
    }
}

主界面MyFrame.java中的两个类:主界面类MyFrame; 定时器类ChangeImageTask

package com.junlin.exer10;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.List;
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @Description:
 * @author: junlin623
 * @create: 2022-11-27 14:11
 */
public class MyFrame extends JFrame {
    JButton playBtn; //开始按钮
    JButton stopBtn;  //暂停按钮
    JButton continueBtn;  //继续按钮
    MusicPlayer player;  //音乐播放器
    JProgressBar progressBar;   //进度条
    File file = null;  //音乐文件
    String filepath = "D:/onedrive/桌面/Java学习/Java作业/实验/实验九/实验9-音乐播放器/resource/";
    long length;   //表示文件的总字节长度
    JLabel imageLabel;  //顶部图片标签
    JLabel musicLabel;  //音量显示标签
    int cnt = 1;   //当前选择的顶部图片编号

    public MyFrame() {
        super("音乐播放器");
        file = new File("D:\\onedrive\\桌面\\Java学习\\Java作业\\实验\\实验九\\实验9-音乐播放器\\resource\\test.wav");

        length = file.length();  //获取文件的字节大小
        System.out.println("length = " + length);
        initMusicPlayer();   //初始化音乐播放器

        Container contentPane = this.getContentPane();
        contentPane.setBackground(Color.white);
        contentPane.setLayout(null);


        //顶部轮播图
        imageLabel = new JLabel();
        imageLabel.setIcon(new ImageIcon(filepath + "b" + cnt + ".png"));
        imageLabel.setBounds(50,10,700,200);
        contentPane.add(imageLabel);
        Timer timer = new Timer();
        timer.schedule(new ChangeImageTask(this), 0, 1500);


        //上方进度条和按钮区域
        JPanel topPanel = new JPanel();
        topPanel.setLayout(null);
        topPanel.setBounds(50,220,700,200);
        topPanel.setBackground(Color.WHITE);
        contentPane.add(topPanel);
        Border border1 = BorderFactory.createTitledBorder("播放进度");
        topPanel.setBorder(border1);

        //添加进度条
        progressBar = new JProgressBar();
        progressBar.setIndeterminate(false);
        progressBar.setMaximum((int)length);
        progressBar.setStringPainted(true);
        progressBar.setString("0%");
        progressBar.setBounds(20,30,650,20);
        topPanel.add(progressBar);

        //添加按钮
        playBtn = new JButton("播放");
        stopBtn = new JButton("暂停");
        continueBtn = new JButton("继续");
        playBtn.addActionListener(new ButtonHandler(this, player));
        stopBtn.addActionListener(new ButtonHandler(this, player));
        continueBtn.addActionListener(new ButtonHandler(this, player));
        playBtn.setBounds(150,80,80,30);
        stopBtn.setBounds(270,80,80,30);
        continueBtn.setBounds(370,80,80,30);
        topPanel.add(playBtn);
        topPanel.add(stopBtn);
        topPanel.add(continueBtn);

        //下方音量控制区域
        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(null);
        bottomPanel.setBackground(Color.white);
        bottomPanel.setBounds(50,450,700,200);
        contentPane.add(bottomPanel);
        Border border2 = BorderFactory.createTitledBorder("音量控制");
        bottomPanel.setBorder(border2);


        musicLabel = new JLabel("当前音量大小: 100");
        musicLabel.setBounds(10,30,150,20);
        bottomPanel.add(musicLabel);

        JSlider slider=new JSlider(0,100,100);
        slider.setBackground(Color.white);
        slider.setMajorTickSpacing(10);//此方法设置主刻度标记的间隔
        slider.setMinorTickSpacing(5);//设置次刻度标记的间隔
        slider.setPaintLabels(true);//确定是否在滑块上绘制标签
        slider.setPaintTicks(true);//确定是否在滑块上绘制刻度标记
        slider.setBounds(20,80,600,80);
        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
//                System.out.println("当前值:" + slider.getValue());
                synchronized (player) {
//                    System.out.println("当前音量:" + player.newVolumn);
                    musicLabel.setText("当前音量大小:" + slider.getValue());
                    player.newVolumn = -80.0f + 0.86f * slider.getValue();
                }
            }
        });
        bottomPanel.add(slider);

        this.setSize(new Dimension(800,900));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


    public void initMusicPlayer() {
        try {
            player = new MusicPlayer(this, file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//轮播图定时器
class ChangeImageTask extends TimerTask {
    private MyFrame frame;
    public ChangeImageTask(MyFrame frame) {
        this.frame = frame;
    }
    @Override
    public void run() {
        this.frame.cnt += 1;
        if(this.frame.cnt >= 6){
            this.frame.cnt = 1;
        }

        this.frame.imageLabel.setIcon(new ImageIcon(this.frame.filepath + "b" + this.frame.cnt + ".png"));
        //frame.imageLabel.paintImmediately(frame.imageLabel.getBounds());
    }
}

JavaMain类:

package com.junlin.exer10;


/**
 * @Description:
 * @author: junlin623
 * @create: 2022-11-27 14:10
 */
public class JavaMain {
    public static void main(String[] args) {
        new MyFrame();
    }
}

运行结果:

posted @ 2023-03-06 19:54  junlin623  阅读(849)  评论(0编辑  收藏  举报