音樂播放器
一、所需的外包:
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格式歌曲。
- 多動手寫一些感興趣的項目,會對自己的提升很大,感觸比較大的是多線程這塊,實際用的時候往往情況比學的時候複雜的多。