音乐播放器
一、所需的外包:
jaudiotagger-2.2.6-SNAPSHOT.jar
jl1.0.1.jar
二、实现的具体功能:
- 根据选择的目标目录,导入该目录下的所有.mp3文件,在控制台会显示歌曲的集合;
- 上方列表会显示导入的歌曲的一些详细信息:歌曲名、歌手、专辑和播放时间,双击音乐列表中的歌曲,可以播放该歌曲;
- 下方左侧区域会显示正在播放歌曲的歌曲名和歌手,最右侧区域会显示播放歌曲的时间;
- 列表下方的进度条会根据播放的进度而增加,一首歌曲播放完成,会进行更新;
- 下方按钮分别为,上一首,暂停,下一首和播放模式选择,点击相应按钮会实现相应的功能;
- 播放模式分为:单曲循环播放,列表循环播放,随机播放;
- 最小化时,播放器会最小化到系统托盘区域,双击或者点击右键->显示主页面,会显示播放器,并退出托盘区域。
三、关于一些需要注意的问题
1.关于播放和暂停
- 该播放方法会造成线程的阻塞,对播放歌曲的播放,应该重新开一个线程;
- 由于不存在暂停功能,我的解决方法是通过设置变量控制线程类的park()方法来阻塞线程,再通过主线程调用unpark()来解除该线程的阻塞,来达到暂停和播放的功能;
- 对于停止播放,直接调用该类的close()方法即可。
2.关于进度条
- 使用标签JLabel类的setBounds(),根据计算的播放的时间和总时间之间的得到已播放百分比,根据设置宽度来改变显示的jlabel的长度达到播放进度的功能;
- 使用定时器TimerTask来计算播放的时间以及每秒更新标签位置,并对全局变量已播放的时间进行赋值,可以记录当前播放的进度,用于播放和暂停,将进度条和时间恢复到已播放的位置。
播放器运行的效果
- 初始运行界面
- 导入本地歌曲
- 播放界面
实现代码
项目结构:
播放工具类(播放方法,获取歌曲信息方法,时间格式转化方法):
package com.bxwl.player.comm;
import com.bxwl.player.service.MusicService;
import com.bxwl.player.entity.Music;
import javazoom.jl.player.Player;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.id3.AbstractID3v2Frame;
import org.jaudiotagger.tag.id3.AbstractID3v2Tag;
import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC;
import javax.swing.*;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
/**
* 音乐播放的工具类
*
* @author bxwl
* @create 2020-07-26 21:25
*/
public class MP3Utils {
/**
* 创建播放器对象
*/
private static Player player;
/**
* 创建歌曲对象
*/
private static MP3File file;
/**
* 当前播放对象
*/
private static Music music;
/**
* 播放状态
*/
private volatile static boolean statue = true;
/**
* 对线程控制
*/
private volatile static AtomicBoolean pause = new AtomicBoolean(false);
/**
* 标记歌曲是否单曲循环播放
*/
private static boolean loop = false;
/**
* 标记是否随机播放
*/
private static boolean random = false;
/**
* 随机数对象
*/
private static Random ran = new Random();
/**
* 是否停止播放
*/
private static boolean stop = false;
/**
* 设置控制线程的变量
* @param b
*/
public static void setPause(boolean b) {
pause.set(b);
}
public static Music getPlaying() {
return music;
}
public static void setPlaying(Music m) {
music = m;
}
/**
* 返回播放器对象
* @return
*/
public static Player getPlayer() {
return player;
}
public static void SetLoop(boolean loop) {
MP3Utils.loop = loop;
}
public static void setRandom(boolean random) {
MP3Utils.random = random;
}
public static boolean isStatue() {
return statue;
}
public static void setStatue(boolean statue) {
MP3Utils.statue = statue;
}
public static void setStop(boolean stop) {
MP3Utils.stop = stop;
}
/**
* 开始播放
*/
public static void play(Music m) {
setPlaying(m);
//存储播放歌曲的集合
List<Music> lists = new ArrayList<>();
//标记歌曲列表中当前播放歌曲
boolean flag = false;
//列表循环
for (int i = 0; i < MusicService.list.size(); i++) {
Music misic = MusicService.list.get(i);
if (m.getId() == misic.getId()) {
flag = true;
}
//将当前播放的歌曲及后面的放入播放集合
if (flag) {
lists.add(misic);
}
}
Runnable r = new Runnable() {
//播放集合中的索引
int index = 0;
@Override
public void run() {
try {
//字节输入流读取音频文件
InputStream is = new FileInputStream(lists.get(index).getPath());
//字节流转字符流
BufferedInputStream bis = new BufferedInputStream(is);
//创建播放器对象
player = new Player(bis);
statue = true;
stop = false;
while (statue) {
while (!pause.get()) {
//暂停(线程阻塞)
if (pause.get()) {
LockSupport.park();
setPause(false);
}
if(stop){
System.out.println("stop");
statue = false;
stop = false;
player.close();
play(m);
}
synchronized (this){
//播放到末尾或者停止播放
if (!player.play(1)) {
System.out.println("finsh");
statue = false;
player.close();
break;
}
}
}
}
Thread.sleep(500);
//判断是否循环,不单曲循环,则列表循环循环,索引增加
if (!loop) {
//播放到最后一首
if (index == lists.size() - 1) {
index = -1;
}
index++;
if (random) {
//随机播放
index = getRandom(lists.size());
}
//设置正在播放的歌曲
setPlaying(lists.get(index));
}
//使用当前Runnable启动新线程
Thread d = new Thread(this);
d.start();
Thread.interrupted();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
Thread.interrupted();
}
}
};
Thread th = new Thread(r);
th.start();
//获取线程状态信息,主线程唤醒播放线程
if (!pause.get()) {
LockSupport.unpark(null);
}
}
/**
* 根据索引获取一个随机数
* @param size
* @return
*/
private static int getRandom(int size) {
return ran.nextInt(size);
}
/**
* 获取歌曲的相关信息
* @param m
* @return
*/
public static Music getMusicInfo(Music m) {
String path = m.getPath();
try {
file = new MP3File(path);
//获取歌曲名
String name = file.getID3v2Tag().frameMap.get("TIT2").toString();
m.setName(name.substring(6, name.length() - 3));
//获取歌曲演唱者
String singer = file.getID3v2Tag().frameMap.get("TPE1").toString();
m.setSinger(singer.substring(6, singer.length() - 3));
//获取歌曲专辑
String album = file.getID3v2Tag().frameMap.get("TALB").toString();
m.setAlbum(album.substring(6, album.length() - 3));
//获取歌曲时长
MP3AudioHeader audioHeader = (MP3AudioHeader) file.getAudioHeader();
m.setTime(audioHeader.getTrackLength());
} catch (IOException e) {
e.printStackTrace();
} catch (TagException e) {
e.printStackTrace();
} catch (ReadOnlyFileException e) {
e.printStackTrace();
} catch (InvalidAudioFrameException e) {
e.printStackTrace();
} catch (CannotReadException e) {
e.printStackTrace();
}
return m;
}
/**
* 获取歌曲封面图片
*
* @param m
* @param dir
* @return
*/
@Deprecated
public ImageIcon saveMusicImage(Music m, File dir) {
FileOutputStream fos = null;
ImageIcon icon = null;
try {
file = new MP3File(m.getPath());
//创建存储图片的文件
File target = new File(dir, m.getName() + "_cover.jpg");
if (!target.exists()) {
target.createNewFile();
}
AbstractID3v2Tag tag = file.getID3v2Tag();
AbstractID3v2Frame frame = (AbstractID3v2Frame) tag.getFrame("APIC");
FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody();
byte[] imageData = body.getImageData();
Image img = Toolkit.getDefaultToolkit().createImage(imageData, 0, imageData.length);
icon = new ImageIcon(img);
fos = new FileOutputStream(target);
fos.write(imageData);
} catch (IOException e) {
e.printStackTrace();
} catch (TagException e) {
e.printStackTrace();
} catch (ReadOnlyFileException e) {
e.printStackTrace();
} catch (CannotReadException e) {
e.printStackTrace();
} catch (InvalidAudioFrameException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return icon;
}
/**
* 时间格式转换
*/
public static String timeChange(int second) {
int min = second / 60;
int sec = second - min * 60;
String rt1 = String.format("%02d", min);
String rt2 = String.format("%02d", sec);
String rt = rt1 + ":" + rt2;
return rt;
}
}
播放模式枚举:
package com.bxwl.player.comm;
/**
* @author bxwl
* @create 2020-07-27 19:20
*/
public enum PlayModel {
SINGLE(1,"单曲循环"),
LIST(2,"列表循环"),
RANDOM(3,"随机播放");
private final int i;
/**模式*/
private final String model;
private PlayModel(int i,String model){
this.i = i;
this.model = model;
}
public String getModelString(){
return model;
}
}
存放歌曲的对象实体类:
package com.bxwl.player.entity;
/**
* @author bxwl
* @create 2020-07-23 19:07
*/
public class Music {
/**id*/
private int id;
/**歌曲名*/
private String name;
/**歌手*/
private String singer;
/**歌曲时长*/
private long time;
/**歌曲绝对路径名*/
private String path;
/**歌曲所属专辑*/
private String album;
public Music() {
}
public Music(int id, String path) {
this.id = id;
this.path = path;
}
public Music(int id, String name, String singer, long time, String path, String album) {
this.id = id;
this.name = name;
this.singer = singer;
this.time = time;
this.path = path;
this.album = album;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSinger() {
return singer;
}
public void setSinger(String singer) {
this.singer = singer;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
@Override
public String toString() {
return "Music{" +
"id=" + id +
", name='" + name + '\'' +
", singer='" + singer + '\'' +
", time=" + time +
", path='" + path + '\'' +
", album='" + album + '\'' +
'}';
}
}
用于对歌曲的存储操作的类:
package com.bxwl.player.service;
import com.bxwl.player.entity.Music;
import java.util.LinkedList;
import java.util.List;
/**
* @author bxwl
* @create 2020-07-25 09:52
*/
public class MusicService {
/**
* 用于存储歌曲的列表
*/
public static List<Music> list = new LinkedList<>();
/**
* 添加歌曲到列表
* @param m
* @return
*/
public boolean addMusic(Music m) {
if (list.size() != 0) {
for (Music music : list) {
if (m.getName().equals(music.getName()) && m.getSinger().equals(music.getSinger())) {
return false;
}
}
}
return list.add(m);
}
/**
* 根据歌曲id从列表移出
* @param id
* @return
*/
public boolean deleteMusicById(int id) {
Music m = null;
if (list.size() != 0) {
for (Music music : list) {
if (id == music.getId()) {
m = music;
break;
}
}
}
if (m == null) {
return false;
}
list.remove(m);
return true;
}
public Music getMusicById(int id){
if (list.size() != 0) {
for (Music music : list) {
if (id == music.getId()) {
return music;
}
}
}
return null;
}
}
主窗体设计类:
package com.bxwl.player.ui;
import com.bxwl.player.comm.MP3Utils;
import com.bxwl.player.comm.PlayModel;
import com.bxwl.player.entity.Music;
import com.bxwl.player.service.MusicService;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
/**
* @author bxwl
* @create 2020-07-23 19:14
*/
public class MusicFrame extends JFrame implements ActionListener {
private MusicService mm = new MusicService();
/**
* 歌曲id
*/
private int id = 1;
/**
* 播放按钮
*/
private JButton playBtn;
/**
* 标记播放按钮是否被点击
*/
private boolean isPlayBtn = true;
/**
* 上一曲
*/
private JButton lastBtn;
/**
* 下一曲
*/
private JButton nextBtn;
/**
* 导入目录中的歌曲按钮
*/
private JButton openFileBtn;
/**
* 播放模式选择按钮
*/
private JButton playModelBtn;
/**
* 显示歌曲的列表
*/
private JTable playTable;
/**
* 进度条
*/
private JLabel timeBar;
/**
* 默认播放模式
*/
private PlayModel model = PlayModel.LIST;
/**
* 显示歌曲名文本
*/
private JTextArea musicNamejta;
/**
* 显示歌曲时间文本
*/
private JTextArea runtime;
/**
* 显示歌曲歌手名文本
*/
private JTextArea musicSingerjta;
/**
* 处理显示时间定时器对象
*/
private Timer showTimeTimer;
/**
* 显示正在播放的歌曲的定时器对象
*/
private Timer showMusicInfoTimer;
/**
* 已播放时间
*/
private volatile int time = 0;
/**
* 托盘图标对象
*/
private TrayIcon trayIcon;
/**
* 本操作系统托盘对象
*/
private SystemTray systemTray;
/**
* 歌曲的总播放时间
*/
private int totalTime;
public MusicFrame() {
//设置标题
setTitle("音乐播放器 v1.0.1");
//设置窗体大小
setSize(800, 543);
//禁止窗体调整大小
setResizable(false);
//设置窗体居中
setLocationRelativeTo(null);
//清除布局
setLayout(null);
//控件布局
init();
//关闭窗体同时关闭程序
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//窗体监听
addWindowListener(new WindowAdapter() {
//窗体退出事件
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
//窗体最小化事件
@Override
public void windowIconified(WindowEvent e) {
systemIcon();
//关闭窗体释放该窗体的占用的部分资源
dispose();
}
});
//设置窗体可见
setVisible(true);
}
/**
* 初始化各按钮
*/
public void init() {
//进度条
String timeImgPath = this.getClass().getResource("/img/progressBar.png").getPath();
Icon timeImg = new ImageIcon(timeImgPath);
timeBar = new JLabel(timeImg);
timeBar.setBounds(35, 420, 0, 14);
add(timeBar);
//显示歌曲名文本
musicNamejta = new JTextArea("");
musicNamejta.setBackground(new Color(60, 63, 65));
musicNamejta.setBounds(35, 440, 150, 45);
//字体颜色
musicNamejta.setForeground(Color.black);
add(musicNamejta);
//显示歌手文本
musicSingerjta = new JTextArea("");
musicSingerjta.setBackground(new Color(60, 63, 65));
musicSingerjta.setBounds(186, 440, 100, 45);
//字体颜色
musicSingerjta.setForeground(Color.black);
add(musicSingerjta);
//上一首按钮
lastBtn = new JButton();
//获取图标地址
String lastBtnImgPath = this.getClass().getResource("/img/last.png").getPath();
//创建上一首图标对象
Icon lastBtnImg = new ImageIcon(lastBtnImgPath);
//设置上一首图标
lastBtn.setIcon(lastBtnImg);
//设置按钮位置、大小
lastBtn.setBounds(300, 440, lastBtnImg.getIconWidth(), lastBtnImg.getIconHeight()); //设置播放按钮大小
//设置不填充
lastBtn.setContentAreaFilled(false);
//不绘制边框
lastBtn.setBorderPainted(false);
//设置按钮边框
lastBtn.setMargin(new Insets(0, 0, 0, 0));
//设置按钮的标签
lastBtn.setActionCommand("上一曲");
//添加按钮监听器
lastBtn.addActionListener(this);
//添加播放按钮至窗口中
add(lastBtn);
//播放/暂停按钮
playBtn = new JButton();
String playBtnImgPath = this.getClass().getResource("/img/play.png").getPath();
Icon playBtnImg = new ImageIcon(playBtnImgPath);
playBtn.setIcon(playBtnImg);
playBtn.setBounds(352, 440, playBtnImg.getIconWidth(), playBtnImg.getIconHeight());
playBtn.setContentAreaFilled(false);
playBtn.setBorderPainted(false);
playBtn.setMargin(new Insets(0, 0, 0, 0));
playBtn.setActionCommand("播放");
playBtn.addActionListener(this);
add(playBtn);
//下一首按钮
nextBtn = new JButton();
String nextBtnImgPath = this.getClass().getResource("/img/next.png").getPath();
Icon nextBtnImg = new ImageIcon(nextBtnImgPath);
nextBtn.setBounds(405, 440, nextBtnImg.getIconWidth(), nextBtnImg.getIconHeight());
nextBtn.setIcon(nextBtnImg);
nextBtn.setContentAreaFilled(false);
nextBtn.setBorderPainted(false);
nextBtn.setMargin(new Insets(0, 0, 0, 0));
nextBtn.setActionCommand("下一曲");
nextBtn.addActionListener(this);
add(nextBtn);
//创建播放歌曲列表
playTable = new JTable(){
//单元格无法编辑
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
//设置播放列表背景颜色
playTable.setBackground(new Color(60, 63, 65));
//设置播放列表字体颜色
playTable.setForeground(Color.BLACK);
//添加播放列表的双击事件关联
playTable.addMouseListener(new ListEvent());
// 把列表组件放入滚动面板中来实现滚动功能
JScrollPane jsp = new JScrollPane(playTable);
jsp.setBounds(35, 25, 730, 375);
//设置表格可见
jsp.setViewportView(playTable);
add(jsp);
//播放模式按钮
playModelBtn = new JButton("L");
Font f = new Font("Arial", Font.BOLD, 22);
playModelBtn.setFont(f);
playModelBtn.setForeground(Color.white);
playModelBtn.setBounds(460, 440, 52, 52);
playModelBtn.setBackground(new Color(42, 42, 42));
playModelBtn.setActionCommand("播放模式");
playModelBtn.addActionListener(this);
add(playModelBtn);
//打开获取歌曲列表的目录按钮
openFileBtn = new JButton();
String openFileBtnImgPath = this.getClass().getResource("/img/list.png").getPath();
Icon openFileBtnImg = new ImageIcon(openFileBtnImgPath);
openFileBtn.setBounds(513, 440, openFileBtnImg.getIconWidth(), openFileBtnImg.getIconHeight());
openFileBtn.setIcon(openFileBtnImg);
openFileBtn.setContentAreaFilled(false);
openFileBtn.setBorderPainted(false);
openFileBtn.setMargin(new Insets(0, 0, 0, 0));
openFileBtn.setActionCommand("选择目录");
openFileBtn.addActionListener(this);
add(openFileBtn);
//歌曲播放时间 控件
runtime = new JTextArea(" 00 : 00");
runtime.setBounds(600, 450, 50, 25);
runtime.setBackground(new Color(60, 63, 65));
runtime.setForeground(Color.BLACK);
add(runtime);
}
/**
* 鼠标时间类
*/
class ListEvent extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
//如果鼠标连续点击两次
if (e.getClickCount() == 2) {
if (e.getSource().equals(playTable)) {
//添加双击播放列表中选中的音乐
int index = playTable.getSelectedRow();
//说明正有歌曲在播放
if (MP3Utils.isStatue()) {
//解除暂停按钮的留下的线程阻塞
MP3Utils.setPause(false);
//停止播放
MP3Utils.setStop(true);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
//初始化控件的歌曲信息
musicInit();
//停止时间计算任务
timerStop();
//停止歌曲信息显示定时任务
stopInfoTimer();
//获取点击的歌曲对象
Music music = MusicService.list.get(index);
//播放歌曲
MP3Utils.play(music);
//开启歌曲信息显示定时任务
infoShowTask(music);
}
}
}
}
/**
* 歌曲信息初始化
*/
public void musicInit() {
//按钮标志为播放状态
isPlayBtn = true;
//已播放时间重置
time = 0;
}
/**
* 用于歌曲信息更新显示的定时任务
*
* @param m
*/
public void infoShowTask(Music m) {
showMusicInfoTimer = new Timer();
//第一首歌曲的播放时间
totalTime = (int) m.getTime();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
//启动定时任务
showMusicInfoTimer.schedule(new TimerTask() {
//临时存储播放的歌曲
Music tempMusic = m;
//标记是否换歌
boolean flag = true;
@Override
public void run() {
Music m = MP3Utils.getPlaying();
if(flag){
totalTime = (int) tempMusic.getTime();
addMusicInfo(tempMusic);
//开始时间计时
timerFun(tempMusic);
flag = false;
System.out.println("播放时间:"+MP3Utils.timeChange(totalTime));
System.out.println("歌曲名:"+tempMusic.getName());
}
if(tempMusic.getId() != m.getId()){
tempMusic = m;
flag = true;
musicInit();
timerStop();
}
}
}, 0, 1000);
}
/**
* 歌曲信息显示任务停止
*/
public void stopInfoTimer() {
if (showMusicInfoTimer != null) {
showMusicInfoTimer.cancel();
}
}
@Override
public void actionPerformed(ActionEvent e) {
//获取点击按钮标签
String cmd = e.getActionCommand();
if ("上一曲".equals(cmd)) {
System.out.println("上一曲");
Music m = MP3Utils.getPlaying();
int index = -1;
//查找当前播放歌曲所在集合的索引
for (int i = 0; i < MusicService.list.size(); i++) {
if (m.getId() == MusicService.list.get(i).getId()) {
index = i;
}
}
//说明正有歌曲在播放
if (MP3Utils.isStatue()) {
//解除暂停按钮的留下的线程阻塞
MP3Utils.setPause(false);
//停止播放
MP3Utils.setStop(true);
}
try {
Thread.sleep(1500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
m = MusicService.list.get(index - 1);
//各信息初始化
musicInit();
timerStop();
//播放歌曲
MP3Utils.play(m);
//歌曲信息更新显示定时任务启动
infoShowTask(m);
} else if ("播放".equals(cmd)) {
if (isPlayBtn) {
System.out.println("暂停");
if (MP3Utils.getPlayer() != null) {
//暂停,线程阻塞
MP3Utils.setPause(true);
isPlayBtn = false;
timerStop();
stopInfoTimer();
}
} else {
System.out.println("播放");
if (MP3Utils.getPlayer() != null) {
//解除线程阻塞
MP3Utils.setPause(false);
isPlayBtn = true;
infoShowTask(MP3Utils.getPlaying());
}
}
} else if ("下一曲".equals(cmd)) {
System.out.println("下一曲");
Music m = MP3Utils.getPlaying();
int index = -1;
for (int i = 0; i < MusicService.list.size(); i++) {
if (m.getId() == MusicService.list.get(i).getId()) {
index = i;
}
}
//说明正有歌曲在播放
if (MP3Utils.isStatue()) {
//解除暂停按钮的留下的线程阻塞
MP3Utils.setPause(false);
//停止播放
MP3Utils.setStop(true);
}
try {
Thread.sleep(1500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
m = MusicService.list.get(index + 1);
musicInit();
timerStop();
MP3Utils.play(m);
infoShowTask(m);
} else if ("播放模式".equals(cmd)) {
setPlayModel();
} else if ("选择目录".equals(cmd)) {
//创建文件选择器对象
JFileChooser fileChooser = new JFileChooser("D:\\");
//设置窗体的批准按钮
fileChooser.setApproveButtonText("确定");
//只允许选择目录
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//弹出一个“打开文件”文件选择器对话框
int returnVal = fileChooser.showOpenDialog(fileChooser);
File selectFile = fileChooser.getSelectedFile();
//确认当前所选文件夹后
if (returnVal == JFileChooser.APPROVE_OPTION) {
//将所选目录下的歌曲添加到集合
addMusicToList(selectFile);
//在列表中显示集合中的歌曲
addMusicToList();
}
System.out.println(MusicService.list);
}
}
/**
* 添加指定目录下的所有歌曲到集合
* @param dir
*/
public void addMusicToList(File dir) {
File[] files = dir.listFiles();
if (files != null) {
for (File f : files) {
if (f.isFile()) {
if (f.getName().endsWith(".mp3") || f.getName().endsWith(".au") || f.getName().endsWith(".wav")) {
Music m = new Music(id++, f.getAbsolutePath());
m = MP3Utils.getMusicInfo(m);
mm.addMusic(m);
}
} else {
addMusicToList(f);
}
}
}
}
/**
* 将歌曲集合显示在列表组件中
*/
public void addMusicToList() {
//获取播放总的歌曲数目
int rowCount = MusicService.list.size();
//设置表头
String[] head = new String[]{"序号", "歌曲名", "歌手", "专辑", "播放时间"};
//添加首行元素数据
DefaultTableModel model = new DefaultTableModel(head, 0);
//添加歌曲信息到表格
for (int j = 0; j < rowCount; j++) {
Vector<String> vt = new Vector<>();
int k = j + 1;
Music m = MusicService.list.get(j);
vt.add(k + "");
vt.add(m.getName());
vt.add(m.getSinger());
vt.add(m.getAlbum());
vt.add(MP3Utils.timeChange((int) m.getTime()));
model.addRow(vt);
}
playTable.setModel(model);
//设置表格行高
playTable.setRowHeight(20);
//设置表格各列的宽度
playTable.getColumnModel().getColumn(0).setPreferredWidth(15);
playTable.getColumnModel().getColumn(1).setPreferredWidth(245);
playTable.getColumnModel().getColumn(2).setPreferredWidth(100);
playTable.getColumnModel().getColumn(3).setPreferredWidth(100);
playTable.getColumnModel().getColumn(4).setPreferredWidth(20);
//隐藏网格线
playTable.setShowGrid(false);
// 更新表格
playTable.invalidate();
}
/**
* 添加歌曲信息到对应组件
*
* @param m
*/
public void addMusicInfo(Music m) {
//将歌曲名显示
musicNamejta.setText("\r\n"+m.getName());
//将歌手信息显示
musicSingerjta.setText("\r\n"+m.getSinger());
}
/**
* 时间定时器,计算歌曲播放时间
* @param m
*/
public void timerFun(Music m) {
timerStop();
//创建定时器
showTimeTimer = new Timer();
//创建定时任务
showTimeTimer.schedule(new TimerTask() {
int startTime = time;
public void run() {
//播放完
if (totalTime == startTime) {
startTime = 0;
time = 0;
timeBar.setBounds(35, 420, 0, 14);
timeBar.validate();
this.cancel();
}
//根据时长设置进度条显示的长度
timeBar.setBounds(35, 420, (int) (((startTime * 1.0) / totalTime) * 730), 14);
//重新布置该组件
timeBar.validate();
String rt = MP3Utils.timeChange(startTime);
runtime.setText(" "+rt);
startTime += 1;
time = startTime;
}
}, 0, 1000);
}
/**
* 停止计时器
*/
public void timerStop() {
if (showTimeTimer != null) {
showTimeTimer.cancel();
}
timeBar.setBounds(35, 420, 0, 14);
timeBar.validate();
}
/**
* 播放模式
*/
public synchronized void setPlayModel() {
if (model == PlayModel.LIST) {
//更新按钮图标
playModelBtn.setText("S");
MP3Utils.setRandom(false);
MP3Utils.SetLoop(true);
//设置播放模式
model = PlayModel.SINGLE;
} else if (model == PlayModel.SINGLE) {
playModelBtn.setText("R");
MP3Utils.SetLoop(false);
MP3Utils.setRandom(true);
model = PlayModel.RANDOM;
} else if (model == PlayModel.RANDOM) {
playModelBtn.setText("L");
MP3Utils.setRandom(false);
MP3Utils.SetLoop(false);
model = PlayModel.LIST;
}
System.out.println(model.getModelString());
}
/**
* 为程序设置系统托盘
*/
private void systemIcon() {
try {
//判断系统是否支持系统托盘功能
if (SystemTray.isSupported()) {
//创建菜单图标
URL resource = this.getClass().getResource("/img/Audios.png");
ImageIcon img = new ImageIcon(resource);
//创建弹出菜单对象
PopupMenu popupMenu = new PopupMenu();
//打开主界面菜单
MenuItem item = new MenuItem("打开主界面");
popupMenu.add(item);
item.addActionListener(e -> {
// 从系统的托盘实例中移除托盘图标
systemTray.remove(trayIcon);
//置此 frame 的状态,该状态表示为逐位掩码
setExtendedState(JFrame.NORMAL);
setVisible(true);
toFront();
});
//退出菜单添加
MenuItem item2 = new MenuItem("退出");
popupMenu.add(item2);
item2.addActionListener(e -> System.exit(0));
// 托盘图标
trayIcon = new TrayIcon(img.getImage(), "音乐播放器", popupMenu);
//双击事件
trayIcon.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
//双击托盘菜单事件
if (e.getClickCount() == 2) {
// 从系统的托盘实例中移除托盘图标
systemTray.remove(trayIcon);
//置此 frame 的状态,该状态表示为逐位掩码
setExtendedState(JFrame.NORMAL);
setVisible(true);
toFront();
}
}
});
//本操作系统托盘的实例
systemTray = SystemTray.getSystemTray();
//托盘图标添加到系统托盘实例
systemTray.add(trayIcon);
}
} catch (AWTException e) {
e.printStackTrace();
}
}
}
注意:对于系统托盘栏乱码问题:在运行配置处设置VM options为"-Dfile.encoding=GB18030"即可
总结
- java不太适合用于实现图形界面,可以作为乐趣来学习;
- 存在一些小的bug,例如:上一曲、下一曲以及双击播放列表切歌时的停顿会有杂音的问题,是由于线程问题引起的。
- 对于播放所依赖的包,自我感觉用的不太舒服,没有提供暂停的方法,好处是可以直接播放.mp3格式歌曲,而java自带的AudioClip,对播放格式有要求,无法播放主流的.mp3格式歌曲。
- 多动手写一些感兴趣的项目,会对自己的提升很大,感触比较大的是多线程这块,实际用的时候往往情况比学的时候复杂的多。