教你轻松制作java音乐播放器
作者:lijiao 发布时间:2023-09-27 11:17:11
标签:java,播放器
一、音乐播放器的实现原理
Javase的多媒体功能很弱,所以有一个专门处理多媒体的插件叫JMF,JMF提供的模型可大致分为七类
* 数据源(Data source)
* 截取设备(Capture Device,包括视频和音频截取设备)
* 播放器(Player)
* 处理器(Processor)
* 数据池(DataSink)
* 数据格式(Format)
* 管理器(Manager)
而我所做的这个音乐播放器MyMusicPlayer(这是我创建的类名)正是调用了JMF中的Player类来实现其播放等各种功能.
我们首先要做的就是要安装JMF。JMF的安装,相信对于许多的新手来说是很伤脑筋的,JMF只支持32位的JDK版本,然而像eclipse这样的IDE环境要与JDK对应,也就是IDE环境要支持32位JDK版本。当安装完JMF之后,有时候对于MP3的播放并不成功,还需要装JMF的mp3plugin。
二、界面效果图
三、功能结构图
四、各种实现功能的代码
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={"顺序播放","单曲循环","随机播放"}; //下拉列表选项数组
JComboBox select=new JComboBox(s); //创建下拉选项
JPanel p1=new JPanel(); //播放列表区域
JPanel p=new JPanel();
JPanel p2=new JPanel(); //按钮区域
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; //播放列表的下标
int count;
int flag; //标记是随机播放还是顺序播放
int countSecond; //获取音乐的总时间值
static int newtime = 0;
int ischanging = 0; //当鼠标是对游标进行点击,进度值也会改变
int ispressing = 0; //判断鼠标是否对游标进行点击
File MusicName = null;
static java.util.List<File> MusicNames = null; //运用泛型,创建File对象
File currentDirectory = null;
List list;// 文件列表
FileDialog open; // 定义文件对话框对象
Random rand = new Random();
String filename;
//进度条
JButton timeInformation = new JButton();
JSlider timeSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 0); //(SwingConstants.HORIZONTAL)用于定向进度条为水平方向的常量的集合
//( 0, 100, 0)用指定的最小值、最大值和初始值创建一个水平滑块。
// 播放
Player player = null;
MusicFileChooser fileChooser = new MusicFileChooser();
static JTextPane tp=new JTextPane(); //显示歌词区域
static JTextArea are=new JTextArea(); //显示图片区域
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); //设置显示播放的歌曲
p6.add(l);
/*实现图片插入
* */
ImageIcon ic=new ImageIcon("image\\2.3.jpg");
ic=new ImageIcon(ic.getImage().getScaledInstance(880, 477, 2)); //获取图片以及设置图片大小
lb=new JLabel(ic);
lb.setOpaque(false);
pp.setOpaque(false); //设置为透明
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); //列表区域
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);
/*
* 实现进度条
* */
timeSlider.setMajorTickSpacing(1);//调用此方法设置主刻度标记的间隔。传入的数字表示在每个主刻度标记之间以值衡量的距离。
timeSlider.setPaintTicks(true); //要绘制主刻度,setPaintTicks 必须设置为 true
timeSlider.addChangeListener(new ChangeListener() { //创建一个新的 ChangeListener 添加到滑块。
public void stateChanged(ChangeEvent arg0) {
if (player != null && ispressing == 1) {
newtime = (int)((JSlider)arg0.getSource()).getValue();
timeInformation.setText("当前时间:"+newtime/60+":"+newtime%60+" || "+" 总时间: "+countSecond/60+":"+countSecond%60);
ischanging = 1;
}
}
});
timeSlider.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent arg0) {
ispressing = 1; //当鼠标对游标进行点击时
}
public void mouseReleased(MouseEvent arg0) {
ispressing = 0; //当鼠标不对游标进行点击时
}
});
timeInformation.setText("当前时间:00:00 || 总时间: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);
}
/*
* 主函数
* */
public static void main(String[] args) throws IOException, InterruptedException { //InterruptedException:当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出该异常
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(); //获取当前路径
if (cd != this.currentDirectory|| this.currentDirectory == null) {
FileFilter[] fileFilters = fileChooser.getChoosableFileFilters(); //FileFilter 是一个抽象类,JFileChooser 使用它过滤显示给用户的文件集合
File files[] = cd.listFiles(); //cd.listFiles()表示返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
this.MusicNames = new ArrayList<File>();
for (File file : files) { //每次循环都将数组中的文件对象赋给file这个变量,然后再在循环体中对这个变量进行操作如:
//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); //定义歌曲的下标
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("当前时间:00:00 || 总时间:00:00");
timeSlider.setValue(0);
player.setMediaTime(new Time(0)); //设置时间为零
}
}
if(e.getSource()==BMoveNext){ //下一曲
if (player != null) {
if("顺序播放".equals(box)){
nextMusic();
}
if("随机播放".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(); //若点击上一曲,则将当前的歌曲停止播放,播放上一曲
try {
player=Manager.createRealizedPlayer(MusicNames.get(index).toURI().toURL());
player.prefetch();
player.setMediaTime(new Time(0.0));// 从某个时间段开始播放
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("随机播放".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(); //若点击上一曲,则将当前的歌曲停止播放,播放上一曲
try {
player=Manager.createRealizedPlayer(MusicNames.get(index).toURI().toURL());
player.prefetch();
player.setMediaTime(new Time(0.0));// 从某个时间段开始播放
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;
}
//双击列表时实现播放
list.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// 双击时处理
if (e.getClickCount() == 2) {
if(player!=null){
player.stop();
}
// 播放选中的文件
index=list.getSelectedIndex();
PlayFile();
}
}
});
}
// 因为实现了"ControllerListener"接口,本方法用于处理媒体播放器传来的事件;
public void controllerUpdate(ControllerEvent e) {
String box=(String)select.getSelectedItem(); //判断播放的顺序
if (e instanceof EndOfMediaEvent) {
player.setMediaTime(new Time(0));
if ("单曲循环".equals(box)) {
player.start();
}
if("顺序播放".equals(box)){
nextMusic();
}
if("随机播放".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));// 从某个时间段开始播放
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;
}
/**
* 下一首 实现函数
*/
public void nextMusic() {
}
/**
* 上一首实现函数
*/
public void PreviousMusic() {
}
/**
* 播放MP3文件主函数
*/
public void PlayFile() {
try {
player = Manager.createRealizedPlayer(MusicNames.get(index).toURI().toURL());
player.prefetch();
player.setMediaTime(new Time(0.0));// 从某个时间段开始播放
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) { //当选到一首音乐不能播放时,对其进行处理
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文件筛选内部类
*/
class MusicFileChooser extends JFileChooser {
}
/**
* MP3文件筛选辅助内部类
*
*/
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;
}
}
/**
* 读取显示时间进度条
*/
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("当前时间:"+newtime/60+":"+newtime%60+" || "+" 总时间: "+countSecond/60+":"+countSecond%60);
}
}
}
}
}
//实现歌词的线程
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); //将歌词区中显示
doc.setParagraphAttributes(0, doc.getLength(), center, false);
tp.setText("艺术家:" + 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());
}
}
}
五、总的测试效果
如下


猜你喜欢
- 在Android开发中,有时我们需要对SQLite数据库进行增,删,查,找等操作,现在就来简单介绍一下,以下为详细代码。 &nbs
- 什么是显式转换Explicit Conversion就是在将一种类型转换成另外一种类型时,需要额外的代码来完成这种转换。int n = 1;
- 反射和配置文件学习 Spring 的时候,虽然可以知道是通过反射和配置文件的方式来获取 JavaBean 对象,但是一直没有机会自己尝试一次
- 一、使用策略枚举来优化if-else看到网上蛮多人推荐使用策略模式来优化if-else,但我总觉得,搞一堆策略类来优化大批量if-else,
- 本文实例讲述了JDBC基础知识与技巧。分享给大家供大家参考。具体分析如下:1.什么是JDBC?通俗来讲JDBC技术就是通过java程序来发送
- 只是为了研究下idea这款编译器怎么使用。开门见山,说下如何配置这款编译器,不配置也能用,但是强迫症表示不服。下面直入正题:下载与安装就不说
- JAVAWEB dbutils执行sql命令并遍历结果集时不能查到内容的原因及处理方法如下所示:遍历结果集时只遍历bean对象才会只输出第一
- 这个系列我们看看C#中有哪些我们知道,但是又不知道怎么用,又或者懒得去了解的东西,比如这篇我们要介绍的toDictionary和ToLook
- 首先是网页部分,upload_file.jsp<%@ page language="java" import=&q
- 1、如果只是一个简单的springboot demo,用以下配置就行新建config类```import org.springf
- 现有的热修复框架很多,尤以AndFix 和Tinker比较多具体的实现方式和项目引用可以参考网络上的文章,今天就不谈,也不是主要目的今天就来
- 在使用Java Swing开发UI程序时,很有可能会遇到使用带复选框的树的需求,但是Java Swing并没有提供这个组件,因此如果你有这个
- 在日常工作中,我们可能常常需要打印各种文件资料,比如word文档。对于编程员,应用程序中文档的打印是一项非常重要的功能,也一直是一个非常复杂
- Spring中添加计时器的时候根据业务需求可能会需要动态处理触发时间;import org.slf4j.Logger; import org
- 在TextView中添加文本时有时会改变一些文本字体的颜色,今天主要分享三种实现方法及相关优缺点。1、通过html标签改变文本颜色tv.se
- 一、定时任务的使用场景和常见的定时任务某个时间定时处理某个任务、发邮件、短信、消息提醒、订单通知、统计报表等定时任务划分单机定时任务:单机的
- 理解C#中的闭包1、 闭包的含义首先闭包并不是针对某一特定语言的概念,而是一个通用的概念。除了在各个支持函数式编程的语言中,我们会接触到它。
- 今天研究了一下scope的作用域。默认是单例模式,即scope="singleton"。另外scope还有prototy
- 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。什么
- 以前传统的比较方式是遍历图片中的每一个像素,然后进行比对。这样的比对在少量图片的比对上虽然效率低一点,但是也没有什么不好。但是在大量图片比对