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的构造函数。伪代码的其余内容分成五个监听器分区:动作监听器,控制器监听器,菜单项监听器,绘图监听器,窗口监听器。每一个分区分别包含一个或多个方法。
作者:sady出处:论坛责任编辑:
方舟
[ 2003-07-11 11:05 ]
一步一步构建自己的Java媒体播放器
三、编写代码
下面我们把前面的伪代码转换成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”命令启动媒体播放器。图一显示了媒体播放器刚启动之后的界面,图四是正在播放媒体的界面。

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