服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

用java构造自己的媒体播放器

一、概述

首先我们来看看构造这个媒体播放器要达到什么样的目标,确定了目标也就确定了代码量和程序的复杂程度。本文的媒体播放器要达到如下目标:

媒体播放器是一个菜单驱动的简单awt应用。

媒体播放器包含一个“文件”菜单,文件菜单包含三个菜单项:

“打开”,用来打开媒体文件。

“循环”,是播放一次(默认),还是重复播放。

“退出”,退出程序。

媒体播放器可以在多种平台上运行。

媒体播放器的核心功能通过jmf(java media framework)api实现。jmf扩展了j2se平台的多媒体能力,允许java应用和applet截取、回放、转换包括音频和视频在内的多种媒体。jmf支持多种媒体格式,具体请参见supported media formats and capture devices。
二、初步设计

我们把这个媒体播放器的设计分成两个部分:gui设计,伪代码设计。在gui设计中,我们要了解构成程序的各个gui部件。在伪代码设计中,我们用自然语言写出程序运行原理。

2.1 gui设计

媒体播放器的用户界面包含一个主窗口、一个菜单和一个打开文件的对话框。首先我们来看看主窗口的设计。主窗口应该把窗口标题显示为“媒体播放器1.0”,显示“文件”菜单,显示彩色背景的“欢迎”信息。图一显示了程序刚启动时的主窗口。

用java构造自己的媒体播放器



图一:媒体播放器的主窗口

“文件”菜单包含三个菜单项。“打开”菜单显示一个对话框,用来选择媒体文件的位置。“循环”菜单决定媒体文件只播放一次(默认)还是反复播放(当菜单被选中)。最后,“退出”菜单关闭程序。另外,点击主窗口右上角的关闭按钮也可以关闭程序。请参见图二。

用java构造自己的媒体播放器

图二:“文件”菜单

点击“文件/打开”菜单时,“打开媒体文件”对话框出现。选中媒体文件之后,点击“打开”按钮即可打开媒体文件;点击“取消”按钮中止文件打开操作。如图三所示。

用java构造自己的媒体播放器

图三:“打开媒体文件”对话框

除了上面提到的部件之外,媒体播放器还包含一个视觉部件、一个控制面板部件。视觉部件顺序播放媒体文件包含的各帧图像;控制面板部件允许用户暂停、开始媒体文件的回放,或进行其他控制操作,例如查看媒体文件信息。
2.2 伪代码设计

前面我们了解了构成媒体播放器gui的各个部件,下面要开始“设想”一下这个程序的具体构造。在正式编写代码之前,我们先用伪代码的形式写出这个程序的运行过程,以后正式编写代码时只需把伪代码翻译成java代码即可。下面给出了媒体播放器的伪代码描述:

应用的类名称:mediaplayer

超类:frame

监听器分类:动作事件,控制器事件,菜单项事件,绘图事件,窗口事件

main:

* 为mediaplayer对象分配内存。调用mediaplayer构造函数,

创建主窗口(同时,隐含地创建/启动了awt后台线程)

* 结束主程序线程。此时awt线程继续运行。

mediaplayer构造函数:

* 设置主窗口的标题

* 注册窗口监听器,以处理窗口关闭事件

* 创建“文件”菜单

* 创建“打开”菜单项

* 把mediaplayer对象注册成为“打开”菜单项动作事件的监听器

* 把“打开”菜单项加入“文件”菜单。

* 在“文件”菜单中加入一条水平分隔线

* 创建带检查框的“循环”菜单项

* 把mediaplayer对象注册成为“循环”菜单项事件的监听器

* 把“循环”菜单项加入“文件菜单”

* 在“文件”菜单中加入一条水平分隔线

* 按照创建“打开”菜单项的过程,创建“退出”菜单项

* 创建一个菜单条(menubar)

* 把“文件”菜单加入到菜单条

* 把新创建的菜单条设置为主窗口的菜单条

* 把主窗口的大小设置为200*200像素

* 显示主窗口

* 结束构造函数

动作监听器:

当出现动作时:

* 如果动作事件起源于“退出”菜单项,

* 触发一个给窗口监听器的窗口关闭事件

* 返回

* 创建一个“打开媒体文件”对话框

* 把对话框的当前目录设置为上次关闭时的目录

* 显示对话框。这个对话框是一个模式对话框

* 如果用户没有通过对话框选择媒体文件

* 返回

* 保存用户在对话框中选择的目录

* 如果以前已经创建jmf播放器对象

* 关闭该对象

* 根据指定的目录和名字,创建一个使用file:协议的媒体定位器(medialocator)对象,再利用该对象创建一个jmf播放器对象

* 如果出现异常

* 显示错误信息,然后返回

* 把主窗口的标题设置为媒体文件的名字

* 把mediaplayer对象注册为来自jmf播放器对象的控制器事件的监听器

* 让jmf播放器对象预先提取媒体内容

* 返回

控制器监听器:

当控制器被关闭:

* 如果jmf播放器的视觉部件存在,从mediaplayer容器拆除视觉部件

* 如果jmf播放器的控制面板部件存在,从mediaplayer容器拆除控制面板部件

* 返回

当媒体回放结束:

* 如果“循环”菜单被选中

* 复位jmf播放器对象的开始时间

* 让jmf播放器对象开始播放媒体

* 返回

当预提取媒体内容结束:

* jmf播放器对象开始播放媒体

* 返回

当实例化(realize)完成:

* 获取jmf播放器对象的视觉部件

* 如果视觉部件存在,则把它加入到mediaplayer容器的中间

* 获取jmf播放器对象的控制面板部件

* 如果控制面板部件存在,则把它加入到medaplayer容器的南方

* 执行pack()操作

* 返回

菜单项监听器:

当菜单项状态改变:

* 切换“循环”菜单被选中的状态

* 返回

绘画事件监听器:

paint()方法:

* 如果尚未装入媒体文件

* 获得主窗口的宽度和高度

* 用蓝色填充窗口内的区域

* 创建一种字体(dialoginput/粗体),并将它设置为主窗口的字体

* 计算欢迎信息的以像素计的宽度

* 把绘图颜色改成白色

* 在主窗口的中央显示出欢迎信息

* 调用frame超类的paint()方法,确保控制面板部件正确地画出

* 返回

update()方法:

* 调用paint()方法

* 返回

窗口监听器:

windowclosing:

* 调用dispose以执行windowclosed

* 返回

windowclosed:

* 如果已经创建jmf播放器对象

* 关闭jmf播放器对象

* 结束程序

伪代码的前面三行声明了媒体播放器的类名称、超类的名称和mediaplayer类实现的监听器。带有main:前缀的行表示mediaplayer的main()方法。类似地,带有“构造函数:”前缀的行属于mediaplayer的构造函数。伪代码的其余内容分成五个监听器分区:动作监听器,控制器监听器,菜单项监听器,绘图监听器,窗口监听器。每一个分区分别包含一个或多个方法。
三、编写代码

下面我们把前面的伪代码转换成java代码:

import javax.media.*;

import java.awt.*;

import java.awt.event.*;

class mediaplayer extends frame implements actionlistener,

controllerlistener, itemlistener

{

player player;

component vc, cc;

boolean first = true, loop = false;

string currentdirectory;

mediaplayer (string title)

{

super (title);

addwindowlistener

(new windowadapter ()

{

public void windowclosing (windowevent e)

{

// 用户点击窗口系统菜单的关闭按钮

// 调用dispose以执行windowclosed

dispose ();

}

public void windowclosed (windowevent e)

{

if (player != null) player.close ();

system.exit (0);

}

});

menu m = new menu ("文件");

menuitem mi = new menuitem ("打开");

mi.addactionlistener (this);

m.add (mi);

m.addseparator ();

checkboxmenuitem cbmi = new checkboxmenuitem ("循环", false);

cbmi.additemlistener (this);

m.add (cbmi);

m.addseparator ();

mi = new menuitem ("退出");

mi.addactionlistener (this);

m.add (mi);

menubar mb = new menubar ();

mb.add (m);

setmenubar (mb);

setsize (200, 200);

setvisible (true);

}

public void actionperformed (actionevent e)

{

if (e.getactioncommand ().equals ("退出"))

{

// 调用dispose以便执行windowclosed

dispose ();

return;

}

filedialog fd = new filedialog (this, "打开媒体文件",

filedialog.load);

fd.setdirectory (currentdirectory);

fd.show ();

// 如果用户放弃选择文件,则返回

if (fd.getfile () == null) return;

currentdirectory = fd.getdirectory ();

if (player != null)

player.close ();

try

{

player = manager.createplayer (new medialocator

("file:" + fd.getdirectory () + fd.getfile ()));

}

catch (java.io.ioexception e2)

{

system.out.println (e2);

return;

}

catch (noplayerexception e2)

{

system.out.println ("不能找到播放器.");

return;

}

if (player == null)

{

system.out.println ("无法创建播放器.");

return;

}

first = false;

settitle (fd.getfile ());

player.addcontrollerlistener (this);

player.prefetch ();

}

public void controllerupdate (controllerevent e)

{

// 调用player.close()时controllerclosedevent事件出现。

// 如果存在视觉部件,则该部件应该拆除(为一致起见,

// 我们对控制面板部件也执行同样的操作)

if (e instanceof controllerclosedevent)

{

if (vc != null)

{

remove (vc);

vc = null;

}

if (cc != null)

{

remove (cc);

cc = null;

}

return;

}

if (e instanceof endofmediaevent)

{

if (loop)

{

player.setmediatime (new time (0));

player.start ();

}

return;

}

if (e instanceof prefetchcompleteevent)

{

player.start ();

return;

}

if (e instanceof realizecompleteevent)

{

vc = player.getvisualcomponent ();

if (vc != null)

add (vc);

cc = player.getcontrolpanelcomponent ();

if (cc != null)

add (cc, borderlayout.south);

pack ();

}

}

public void itemstatechanged (itemevent e)

{

loop = !loop;

}

public void paint (graphics g)

{

if (first)

{

int w = getsize ().width;

int h = getsize ().height;

g.setcolor (color.blue);

g.fillrect (0, 0, w, h);

font f = new font ("dialoginput", font.bold, 16);

g.setfont (f);

fontmetrics fm = g.getfontmetrics ();

int swidth = fm.stringwidth ("*** 欢迎 ***");

g.setcolor (color.white);

g.drawstring ("*** 欢迎 ***",

(w - swidth) / 2,

(h + getinsets ().top) / 2);

}

// 调用超类frame的paint()方法,该paint()方法将调用frame包含的各个容器

// 和部件(包括控制面板部件)的paint()方法。

super.paint (g);

}

// 不执行背景清除操作,以免控制面板部件闪烁

public void update (graphics g)

{

paint (g);

}

public static void main (string [] args)

{

new mediaplayer ("媒体播放器1.0");

}

}

上述代码的具体含义这里就不再分析。实际上,代码中的注释解释了关键步骤的作用;另外,前面的伪代码也非常接近这里的java代码,可以看作对上述代码的详细解释。
四、编译和运行

假设前面的java代码保存在mediaplayer.java文件中,则编译命令如下:

javac mediaplayer.java

编译成功后,编译器生成两个.class文件:mediaplayer.class,mediaplayer$1.class。如果出现编译错误,请检查以下各项:

源代码输入是否正确无误。

classpath设置是否正确。classpath应当包含jmf的sound.jar、jmf.jar。

接下来就可以执行“java mediaplayer”命令启动媒体播放器。图一显示了媒体播放器刚启动之后的界面,图四是正在播放媒体的界面。

用java构造自己的媒体播放器



图四:用媒体播放器回放mpg电影

扫描关注微信公众号