教你輕松制作java音樂播放器
一、音樂播放器的實(shí)現(xiàn)原理
Javase的多媒體功能很弱,所以有一個專門處理多媒體的插件叫JMF,JMF提供的模型可大致分為七類
* 數(shù)據(jù)源(Data source)
* 截取設(shè)備(Capture Device,包括視頻和音頻截取設(shè)備)
* 播放器(Player)
* 處理器(Processor)
* 數(shù)據(jù)池(DataSink)
* 數(shù)據(jù)格式(Format)
* 管理器(Manager)
而我所做的這個音樂播放器MyMusicPlayer(這是我創(chuàng)建的類名)正是調(diào)用了JMF中的Player類來實(shí)現(xiàn)其播放等各種功能.
我們首先要做的就是要安裝JMF。JMF的安裝,相信對于許多的新手來說是很傷腦筋的,JMF只支持32位的JDK版本,然而像eclipse這樣的IDE環(huán)境要與JDK對應(yīng),也就是IDE環(huán)境要支持32位JDK版本。當(dāng)安裝完JMF之后,有時(shí)候?qū)τ贛P3的播放并不成功,還需要裝JMF的mp3plugin。
二、界面效果圖

三、功能結(jié)構(gòu)圖

四、各種實(shí)現(xiàn)功能的代碼
public class MyMusicPlayer implements ActionListener, ControllerListener,Runnable{
JFrame j=new JFrame("音樂播放器");
JLabel TablePlaer=new JLabel("播放列表");
JButton BAdd=new JButton("添加歌曲");
JButton BDelect=new JButton("刪除歌曲");
JButton BDelectTable=new JButton("清空列表");
JButton BMoveNext=new JButton("下一曲");
JButton BMovePrevious=new JButton("上一曲");
JButton BPlayer=new JButton("暫停");
JButton BStop=new JButton("停止");
JButton BSet=new JButton("顯示歌詞");
JButton BEnd=new JButton("停止");
String[] s={"順序播放","單曲循環(huán)","隨機(jī)播放"}; //下拉列表選項(xiàng)數(shù)組
JComboBox select=new JComboBox(s); //創(chuàng)建下拉選項(xiàng)
JPanel p1=new JPanel(); //播放列表區(qū)域
JPanel p=new JPanel();
JPanel p2=new JPanel(); //按鈕區(qū)域
JPanel p3=new JPanel();
JLabel l=new JLabel();
JPanel p5=new JPanel(); //放置播放列表
JPanel p6=new JPanel(); //放置播放歌曲的名稱
static JPanel pp=new JPanel();
static JLabel lb;
public static JTextArea jt=new JTextArea();
static int index; //播放列表的下標(biāo)
int count;
int flag; //標(biāo)記是隨機(jī)播放還是順序播放
int countSecond; //獲取音樂的總時(shí)間值
static int newtime = 0;
int ischanging = 0; //當(dāng)鼠標(biāo)是對游標(biāo)進(jìn)行點(diǎn)擊,進(jìn)度值也會改變
int ispressing = 0; //判斷鼠標(biāo)是否對游標(biāo)進(jìn)行點(diǎn)擊
File MusicName = null;
static java.util.List<File> MusicNames = null; //運(yùn)用泛型,創(chuàng)建File對象
File currentDirectory = null;
List list;// 文件列表
FileDialog open; // 定義文件對話框?qū)ο?
Random rand = new Random();
String filename;
//進(jìn)度條
JButton timeInformation = new JButton();
JSlider timeSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 0); //(SwingConstants.HORIZONTAL)用于定向進(jìn)度條為水平方向的常量的集合
//( 0, 100, 0)用指定的最小值、最大值和初始值創(chuàng)建一個水平滑塊。
// 播放
Player player = null;
MusicFileChooser fileChooser = new MusicFileChooser();
static JTextPane tp=new JTextPane(); //顯示歌詞區(qū)域
static JTextArea are=new JTextArea(); //顯示圖片區(qū)域
public MyMusicPlayer(){
j.setSize(1200, 700);
j.setLayout(null);
j.getContentPane().setBackground(Color.BLACK);
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p.setBounds(2, 563, 1180, 95);
p.setLayout(new BorderLayout());
p1.setBounds(2, 3, 298, 30);
p1.setBackground(new Color(255,255,255));
p2.setLayout(new GridLayout(2,3,20,20));
p2.setBackground(Color.LIGHT_GRAY);
p3.setLayout(new GridLayout(2,0,200,10));
p3.setBackground(new Color(255,255,255));
p5.setBounds(2, 35, 298, 526);
p5.setLayout(null);
p5.setBackground(new Color(255,255,255));
p6.setBounds(301, 3,880, 30);
p6.setLayout(null);
p6.setBackground(new Color(255,255,255));
l.setBounds(250, 4, 600, 30); //設(shè)置顯示播放的歌曲
p6.add(l);
/*實(shí)現(xiàn)圖片插入
* */
ImageIcon ic=new ImageIcon("image\\2.3.jpg");
ic=new ImageIcon(ic.getImage().getScaledInstance(880, 477, 2)); //獲取圖片以及設(shè)置圖片大小
lb=new JLabel(ic);
lb.setOpaque(false);
pp.setOpaque(false); //設(shè)置為透明
pp.setBounds(241, 80,990, 500);
are.setBounds(241, 56,990, 520);
are.setOpaque(false);
tp.setBackground(new Color(255,255,255));
tp.setBounds(301, 35,880, 49);
pp.add(are);
pp.add(lb);
// 文件列表
list = new List(10);
list.setBounds(100, 55, 187, 495); //列表區(qū)域
list.addActionListener(this);
j.add(list);
j.add(jt);
j.add(tp);
BAdd.setBounds(5,20, 90,30);
BAdd.setBackground(new Color(255,255,255));
BDelect.setBounds(5, 80, 90, 30);
BDelect.setBackground(new Color(255,255,255));
BDelectTable.setBounds(5, 140, 90, 30);
BDelectTable.setBackground(new Color(255,255,255));
TablePlaer.setBounds(30, 100, 200, 50);
TablePlaer.setFont(new Font("宋體",1, 20));
p1.add(TablePlaer);
BMovePrevious.setBackground(new Color(255,255,255));
BPlayer.setBackground(new Color(255,255,255));
BMoveNext.setBackground(new Color(255,255,255));
BStop.setBackground(new Color(255,255,255));
select.setBackground(new Color(255,255,255));
BSet.setBackground(new Color(255,255,255));
p2.add(BMovePrevious);
p2.add(BPlayer);
p2.add(BMoveNext);
p2.add(BStop);
p2.add(select);
p2.add(BSet);
p2.setBackground(new Color(255,255,255));
p.add(p2,BorderLayout.WEST);
p.add(p3,BorderLayout.CENTER);
p5.add(p);
p5.add(BAdd);
p5.add(BDelect);
p5.add(BDelectTable);
BAdd.addActionListener(this);
BDelect.addActionListener(this);
BDelectTable.addActionListener(this);
BMoveNext.addActionListener(this);
BPlayer.addActionListener(this);
BMovePrevious.addActionListener(this);
BStop.addActionListener(this);
select.addActionListener(this);
BSet.addActionListener(this);
timeInformation.setEnabled(false);
/*
* 實(shí)現(xiàn)進(jìn)度條
* */
timeSlider.setMajorTickSpacing(1);//調(diào)用此方法設(shè)置主刻度標(biāo)記的間隔。傳入的數(shù)字表示在每個主刻度標(biāo)記之間以值衡量的距離。
timeSlider.setPaintTicks(true); //要繪制主刻度,setPaintTicks 必須設(shè)置為 true
timeSlider.addChangeListener(new ChangeListener() { //創(chuàng)建一個新的 ChangeListener 添加到滑塊。
public void stateChanged(ChangeEvent arg0) {
if (player != null && ispressing == 1) {
newtime = (int)((JSlider)arg0.getSource()).getValue();
timeInformation.setText("當(dāng)前時(shí)間:"+newtime/60+":"+newtime%60+" || "+" 總時(shí)間: "+countSecond/60+":"+countSecond%60);
ischanging = 1;
}
}
});
timeSlider.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent arg0) {
ispressing = 1; //當(dāng)鼠標(biāo)對游標(biāo)進(jìn)行點(diǎn)擊時(shí)
}
public void mouseReleased(MouseEvent arg0) {
ispressing = 0; //當(dāng)鼠標(biāo)不對游標(biāo)進(jìn)行點(diǎn)擊時(shí)
}
});
timeInformation.setText("當(dāng)前時(shí)間:00:00 || 總時(shí)間:00:00");
timeInformation.setBackground(new Color(255,255,255));
p3.add(timeInformation,BorderLayout.NORTH);
p3.add(timeSlider,BorderLayout.SOUTH);
j.add(pp);
j.add(p5);
j.add(p);
j.add(p1);
j.add(p6);
j.setVisible(true);
// j.setResizable(false);
}
/*
* 主函數(shù)
* */
public static void main(String[] args) throws IOException, InterruptedException { //InterruptedException:當(dāng)線程在活動之前或活動期間處于正在等待、休眠或占用狀態(tài)且該線程被中斷時(shí),拋出該異常
MyMusicPlayer play=new MyMusicPlayer();
Thread timeRun = new Thread(play);
timeRun.start();
}
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand(); //通過獲取字符串來判斷是播放還是暫停,
String box=(String)select.getSelectedItem(); //判斷播放的順序
if(e.getSource()==BAdd)
{
if (player == null) {
if (fileChooser.showOpenDialog(j) == MusicFileChooser.APPROVE_OPTION) {
this.MusicName = fileChooser.getSelectedFile();
File cd = fileChooser.getCurrentDirectory(); //獲取當(dāng)前路徑
if (cd != this.currentDirectory|| this.currentDirectory == null) {
FileFilter[] fileFilters = fileChooser.getChoosableFileFilters(); //FileFilter 是一個抽象類,JFileChooser 使用它過濾顯示給用戶的文件集合
File files[] = cd.listFiles(); //cd.listFiles()表示返回一個抽象路徑名數(shù)組,這些路徑名表示此抽象路徑名表示的目錄中的文件。
this.MusicNames = new ArrayList<File>();
for (File file : files) { //每次循環(huán)都將數(shù)組中的文件對象賦給file這個變量,然后再在循環(huán)體中對這個變量進(jìn)行操作如:
//for(int i=0;i<files.length;i++){ file = files[i];……}
filename = file.getName().toLowerCase(); //獲取所有的音樂名稱
for (FileFilter filter : fileFilters) {
if (!file.isDirectory() && filter.accept(file)) {
this.MusicNames.add(file);
list.add(filename);
filename=e.getActionCommand();
}
}
}
}
index = MusicNames.indexOf(MusicName); //定義歌曲的下標(biāo)
count = MusicNames.size();
PlayFile();
}
} else {
player.start();
}
}
if(cmd.equals("暫停")){
BPlayer.setText("播放");
player.stop();
}
if(cmd.equals("播放")){
BPlayer.setText("暫停");
player.start();
}
if(e.getSource()==BStop){ //停止
if (player != null) {
player.stop();
timeInformation.setText("當(dāng)前時(shí)間:00:00 || 總時(shí)間:00:00");
timeSlider.setValue(0);
player.setMediaTime(new Time(0)); //設(shè)置時(shí)間為零
}
}
if(e.getSource()==BMoveNext){ //下一曲
if (player != null) {
if("順序播放".equals(box)){
nextMusic();
}
if("隨機(jī)播放".equals(box)){
int index = (int) rand.nextInt(this.MusicNames.size())+1;
if (this.MusicNames != null && !this.MusicNames.isEmpty()) {
if ( ++index == this.MusicNames.size()) {
index=(int) rand.nextInt(this.MusicNames.size())+1;
}
player.stop(); //若點(diǎn)擊上一曲,則將當(dāng)前的歌曲停止播放,播放上一曲
try {
player=Manager.createRealizedPlayer(MusicNames.get(index).toURI().toURL());
player.prefetch();
player.setMediaTime(new Time(0.0));// 從某個時(shí)間段開始播放
player.addControllerListener(this);
l.setText("正在播放:"+this.MusicNames.get(index).toString());
list.select(index);
player.start();
flag=1;
} catch (NoPlayerException | CannotRealizeException | IOException e1) {
e1.printStackTrace();
}
}
}
}
}
if(e.getSource()==BMovePrevious){ //上一曲
if (player != null) {
if("順序播放".equals(box)){
PreviousMusic();
}
if("隨機(jī)播放".equals(box)){
int index = (int) rand.nextInt(this.MusicNames.size())+1;
if (this.MusicNames != null && !this.MusicNames.isEmpty()) {
if ( index--==(int) rand.nextInt(this.MusicNames.size())+1) {
index = this.MusicNames.size() - 1;
}
player.stop(); //若點(diǎn)擊上一曲,則將當(dāng)前的歌曲停止播放,播放上一曲
try {
player=Manager.createRealizedPlayer(MusicNames.get(index).toURI().toURL());
player.prefetch();
player.setMediaTime(new Time(0.0));// 從某個時(shí)間段開始播放
player.addControllerListener(this);
l.setText("正在播放:"+this.MusicNames.get(index).toString());
list.select(index);
player.start();
flag=1;
} catch (NoPlayerException | CannotRealizeException | IOException e1) {
e1.printStackTrace();
}
}
}
}
}
if(e.getSource()==BDelect){ //刪除歌曲
index =list.getSelectedIndex();
list.remove(index);
MusicNames.remove(this.index);
}
if(e.getSource()==BDelectTable){ //清空列表
list.removeAll();
MusicNames.removeAll(MusicNames);
player.stop();
player = null;
}
//雙擊列表時(shí)實(shí)現(xiàn)播放
list.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// 雙擊時(shí)處理
if (e.getClickCount() == 2) {
if(player!=null){
player.stop();
}
// 播放選中的文件
index=list.getSelectedIndex();
PlayFile();
}
}
});
}
// 因?yàn)閷?shí)現(xiàn)了"ControllerListener"接口,本方法用于處理媒體播放器傳來的事件;
public void controllerUpdate(ControllerEvent e) {
String box=(String)select.getSelectedItem(); //判斷播放的順序
if (e instanceof EndOfMediaEvent) {
player.setMediaTime(new Time(0));
if ("單曲循環(huán)".equals(box)) {
player.start();
}
if("順序播放".equals(box)){
nextMusic();
}
if("隨機(jī)播放".equals(box)){
if (this.MusicNames != null && !this.MusicNames.isEmpty()) {
int index = (int) rand.nextInt(this.MusicNames.size())+1;
try {
player=Manager.createRealizedPlayer(MusicNames.get(index).toURI().toURL());
player.prefetch();
player.setMediaTime(new Time(0.0));// 從某個時(shí)間段開始播放
player.addControllerListener(this);
l.setText("正在播放:"+this.MusicNames.get(index).toString());
list.select(index);
player.start();
flag=1;
} catch (NoPlayerException | CannotRealizeException | IOException e1) {
e1.printStackTrace();
}
}
}
}
}
/**
* 獲取MP3歌曲名
*
* @MP3文件路徑
* @歌曲名
*/
public String getMusicName(String str) {
int i;
for (i = str.length() - 1; i > 0; i--) {
if (str.charAt(i) == '\\')
break;
}
str = str.substring(i + 1, str.length() - 4);
return str;
}
/**
* 下一首 實(shí)現(xiàn)函數(shù)
*/
public void nextMusic() {
}
/**
* 上一首實(shí)現(xiàn)函數(shù)
*/
public void PreviousMusic() {
}
/**
* 播放MP3文件主函數(shù)
*/
public void PlayFile() {
try {
player = Manager.createRealizedPlayer(MusicNames.get(index).toURI().toURL());
player.prefetch();
player.setMediaTime(new Time(0.0));// 從某個時(shí)間段開始播放
player.addControllerListener(this);
l.setFont(new Font("宋體",0,20));
l.setText("正在播放:"+this.MusicNames.get(index).toString()); //顯示正在播放的歌曲
list.select(index);
player.start();
Mythread11 tt=new Mythread11();
tt.start();
} catch (Exception e1) { //當(dāng)選到一首音樂不能播放時(shí),對其進(jìn)行處理
dealError();
return;
}
this.setFrame();
}
public void setFrame()
{
countSecond = (int)player.getDuration().getSeconds();
timeSlider.setMaximum(countSecond);
timeSlider.setValue(0);
newtime = 0;
}
private void dealError() {
// TODO Auto-generated method stub
MusicNames.remove(index);
if( --count == index )
index = 0;
if( count == 0)
player = null;
else
PlayFile();
}
/**
* MP3文件篩選內(nèi)部類
*/
class MusicFileChooser extends JFileChooser {
}
/**
* MP3文件篩選輔助內(nèi)部類
*
*/
class MyFileFilter extends FileFilter { //FileFilter 是一個抽象類,JFileChooser 使用它過濾顯示給用戶的文件集合
String[] suffarr;
String decription;
public MyFileFilter() {
super();
}
public MyFileFilter(String[] suffarr, String decription) {
super();
this.suffarr = suffarr;
this.decription = decription;
}
public boolean accept(File f) {
for (String s : suffarr) {
if (f.getName().toUpperCase().endsWith(s)) {
return true;
}
}
return f.isDirectory();
}
public String getDescription() {
return this.decription;
}
}
/**
* 讀取顯示時(shí)間進(jìn)度條
*/
public void run() {
while(true) {
sleep();
if(player != null) {
if(ispressing == 0) {
if(ischanging == 1) {
newtime = timeSlider.getValue();
player.setMediaTime(new Time(((long)newtime)*1000000000));
ischanging = 0;
} else {
newtime = (int)player.getMediaTime().getSeconds();
timeSlider.setValue(newtime);
timeInformation.setText("當(dāng)前時(shí)間:"+newtime/60+":"+newtime%60+" || "+" 總時(shí)間: "+countSecond/60+":"+countSecond%60);
}
}
}
}
}
//實(shí)現(xiàn)歌詞的線程
class Mythread11 extends Thread {
public void run() {
// TODO Auto-generated method stub
try{
LRC lrc = ReadLRC.readLRC("Traveling Light.lrc");
Lyrics ls = ParseLRC.parseLRC(lrc);
playTest(ls);
}catch(Exception e){
}
}
}
static void playTest(Lyrics ls) throws InterruptedException {
tp.setFont(new Font("宋體",1,20));
tp.setForeground(Color.BLUE);
StyledDocument doc = tp.getStyledDocument();
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); //將歌詞區(qū)中顯示
doc.setParagraphAttributes(0, doc.getLength(), center, false);
tp.setText("藝術(shù)家:" + ls.getAr());
tp.setText("專輯:" + ls.getAl());
tp.setText("歌曲:" + ls.getTi());
tp.setText("歌詞制作:" + ls.getBy());
for (Lyric l : ls.getLyrics()) {
tp.setText( l.getTxt());
Thread.sleep(l.getTimeSize());
}
}
}
五、總的測試效果
如下

更多關(guān)于播放器的內(nèi)容請點(diǎn)擊《java播放器功能》進(jìn)行學(xué)習(xí)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于ScheduledExecutorService的兩種方法(詳解)
下面小編就為大家?guī)硪黄赟cheduledExecutorService的兩種方法(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
java、js中實(shí)現(xiàn)無限層級的樹形結(jié)構(gòu)方法(類似遞歸)
下面小編就為大家?guī)硪黄猨ava、js中實(shí)現(xiàn)無限層級的樹形結(jié)構(gòu)方法(類似遞歸)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11
SpringBoot使用Spring Security實(shí)現(xiàn)登錄注銷功能
這篇文章主要介紹了SpringBoot使用Spring Security實(shí)現(xiàn)登錄注銷功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-09-09
對java for 循環(huán)執(zhí)行順序的詳解
今天小編就為大家分享一篇對java for 循環(huán)執(zhí)行順序的詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06
Java?file類中renameTo方法操作實(shí)例
renameTo()方法是File類的一部分,renameTo()函數(shù)用于將文件的抽象路徑名重命名為給定的路徑名??,下面這篇文章主要給大家介紹了關(guān)于Java?file類中renameTo方法操作的相關(guān)資料,需要的朋友可以參考下2022-11-11
springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼
這篇文章主要介紹了springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
java保證對象在內(nèi)存中唯一性的實(shí)現(xiàn)方法
這篇文章主要介紹了java如何保證對象在內(nèi)存中的唯一性,如果創(chuàng)建多個對象的話,可能會引發(fā)出各種各樣的問題,這時(shí),就需要我們保證這個對象在內(nèi)存中的唯一性,需要的朋友可以參考下2019-06-06

