java媒体播放器

山东大学软件学院面向对象设计技术课程的实验之一。(说起来这些实验感觉没有什么太难的地方,基本没有什么实用性。)。(还有一个感受,重修太痛苦,别人两个人写一个,我要一个人写两个。好像我也算不上重修)
模拟实现一个多功能媒体播放器,它能播放音频(如mp3歌曲)、视频(选作,不属于基本要求)。媒体播放器界面,有进度条,可展示总播放时间、当前播放时间,进度条可拖动,有播放、暂停键,有快进、快退键。

文章目录

    • 0 效果
    • 1 解耦
    • 2 界面
      • 2.1 界面组织结构
      • 2.2 重写进度条UI
      • 2.3 面板切换
    • 3 音乐功能
      • 3.1 音乐播放
      • 3.2 播放模式
      • 3.3 通过进度条控制播放进度
      • 3.4 显示歌词
    • 4 视频功能
      • 4.1 实现播放
    • 5 源码

0 效果

这个实验题目很明确,就是放音乐,网上一搜,java播放音乐的代码有的是,视频也有。
先上效果图:
java媒体播放器_第1张图片
java媒体播放器_第2张图片
(最近迷上了花花,全都是花花的歌。。。)
个人感觉完成度比较高吧。
实现的功能:音乐播放、上一首、下一首、随机播放、单曲循环、实时歌词、视频播放。

1 解耦

首先是解耦的过程。先要明确设计好哪些模块。我是按照 内容 -> 样式 -> 行为 的思路写的(基本是按照html -> css -> js的思路)。
不过,内容和样式是一起的而已。
java媒体播放器_第3张图片

2 界面

2.1 界面组织结构

java媒体播放器_第4张图片
第一部分:展示当前播放音频的文件名
第二部分:展示文件列表,包括视频和音频
第三部分:展示歌词信息
第四部分:控制部分,包含各种按钮、进度条等实现播放控制、模式控制等。
显然,视频播放不能在主界面实现,所以需要额外添加一个窗口播放视频,基本的设计与上图相比,仅保留第三、四部分。

2.2 重写进度条UI

我们都知道,java swing的基本组件都很难看,好在可以通过SliderUI来重新设计自己的UI。下面是我的:

package UI;

import Value.PlayerColor; //自己写的类,其中定义了所有的颜色常量

import javax.swing.*;
import javax.swing.plaf.basic.BasicSliderUI;
import java.awt.*;

public class SliderUI extends BasicSliderUI {
     

    public SliderUI(JSlider b) {
     
        super(b);
    }

    @Override
    public void paintThumb(Graphics g) {
      //绘制游标
        Graphics2D g2d = (Graphics2D) g;
        BasicStroke stroke = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2d.setStroke(stroke);
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        GradientPaint gp = new GradientPaint(0, 0, PlayerColor.Default, 0, thumbRect.height, PlayerColor.Default);
        g2d.setPaint(gp);
        g2d.fillOval(thumbRect.x, thumbRect.y + 5, 10, 10);
        BasicStroke stroke1 = new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2d.setStroke(stroke1);
        g2d.drawLine(0, thumbRect.height / 2, thumbRect.x + 8, thumbRect.height / 2);
    }

    @Override
    public void paintTrack(Graphics g) {
      //绘制滑道
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);// 设定渐变
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
        g2d.setPaint(new GradientPaint(0, 0, PlayerColor.SliderStart, 0, trackRect.height, PlayerColor.SliderEnd, true));
        g2d.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2d.drawLine(8, trackRect.height / 2 + 1, trackRect.width + 8, trackRect.height / 2 + 1);
    }
}

2.3 面板切换

实现音乐列表和视频列表的切换。首先,这个不能用基本的JPanel,否则多余的列表项就不会现实出来,得用滑动面板JScrollPane。关于这个JScrollPane的用法,我也是查了好多博客才弄明白,需要注意一下几点:

  1. JScrollPane设置setBounds设置的本身的大小
  2. JScrollPane设置setViewportView(obj)是JScrollPane里面包裹的是obj,不是add方法,添加JScrollPane的时候仍然是add
  3. 内容元素obj要设置setPreferredSize
        scrollPane = new JScrollPane();
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);//设置水平条不出现
        scrollPane.getVerticalScrollBar().setUI(new ScrollBarUI());//重新UI,类似于2.2
        scrollPane.setBounds(0, 100, 300, 600);//设置本身大小
        scrollPane.setViewportView(asideList);
        /*
        asideList是面板,用于容纳每一项,在构造asideList的时候必须有下面的语句,num是列表项的数目:
        setVisible(true);
        setPreferredSize(new Dimension(300, 50 * num));
		*/
        scrollPane.setBorder(null);
        add(scrollPane);

UI

package UI;

import Value.PlayerColor; //自己写的类,其中定义了所有的颜色常量

import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JScrollBar;
import javax.swing.plaf.basic.BasicScrollBarUI;


public class ScrollBarUI extends BasicScrollBarUI {
     
    @Override
    protected void configureScrollBarColors() {
     
        trackColor = PlayerColor.ListEvenItemBackground;
        setThumbBounds(0, 0, 10, 10);
    }

    @Override
    public Dimension getPreferredSize(JComponent c) {
     
        c.setPreferredSize(new Dimension(5, 0));
        return super.getPreferredSize(c);
    }

    @Override
    public void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) {
     
        Graphics2D g2 = (Graphics2D) g;
        GradientPaint gp = null;
        if (this.scrollbar.getOrientation() == JScrollBar.VERTICAL)
            gp = new GradientPaint(0, 0, PlayerColor.ListEvenItemBackground, trackBounds.width, 0, PlayerColor.ListEvenItemBackground);
        g2.setPaint(gp);
        g2.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height);//填充Track
        if (trackHighlight == BasicScrollBarUI.DECREASE_HIGHLIGHT)
            this.paintDecreaseHighlight(g);
        if (trackHighlight == BasicScrollBarUI.INCREASE_HIGHLIGHT)
            this.paintIncreaseHighlight(g);
    }

    @Override
    protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
     
        g.translate(thumbBounds.x, thumbBounds.y);// 这句一定一定要加上,不然拖动就失效了
        g.setColor(PlayerColor.LyricsBackground);// 设置把手颜色
        g.drawRoundRect(0, 0, 5, thumbBounds.height - 1, 5, 5);
        // 消除锯齿
        Graphics2D g2 = (Graphics2D) g;
        RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.addRenderingHints(rh);
        // 半透明
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
        g2.fillRoundRect(0, 0, 40, thumbBounds.height - 1, 5, 5);
    }

    @Override
    protected JButton createIncreaseButton(int orientation) {
     
        JButton button = new JButton();
        button.setBorderPainted(false);
        button.setContentAreaFilled(false);
        button.setBorder(null);
        return button;

    }

    @Override
    protected JButton createDecreaseButton(int orientation) {
     
        JButton button = new JButton();
        button.setBorderPainted(false);
        button.setContentAreaFilled(false);
        button.setFocusable(false);
        button.setBorder(null);
        return button;
    }

}

3 音乐功能

java媒体播放器_第5张图片

3.1 音乐播放

实现mp3播放的有很多方式,我用的是下面这个:

        <dependency>
            <groupId>com.googlecode.soundlibsgroupId>
            <artifactId>mp3spiartifactId>
            <version>1.9.5.4version>
        dependency>

使用方式:

		File file = new File(path);
		FileInputStream stream = new FileInputStream(file);
		Player player = new Player(stream);
		player.play();

但是直接这样子是有问题的。播放之后会阻塞,所以需要新开辟一个线程

3.2 播放模式

上一首、下一首、随机播放、循环播放等,没有什么难点。就是设置几个变量,在一首音乐播放完毕后,检查这几个变量就行。

3.3 通过进度条控制播放进度

没有控制播放进度的功能,我的解决方法是讲音频文件变成字节流,在控制时再将字节流转换成文件流

3.4 显示歌词

使用lrc文件,可以看出很好处理,前面是时间,后面是歌词,单独组织称一个数据结构保存,开辟一个线程控制。
在这里插入图片描述

4 视频功能

视频的实现是用VLC。安装VLC时先看看本身能不能正常播放(我下了一个都不能正常播放,更不用说用代码控制了)

4.1 实现播放

安装好之后发现基本的播放功能VLC都是提供的。而且只要字幕(弹幕)文件和视频放在同一个文件夹下就能自动加载进去,如下图
java媒体播放器_第6张图片

5 源码

此处是源码

你可能感兴趣的:(本科课程,#,面向对象,java)