程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 用Java構造自己的媒體播放器

用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”,顯示“文件”菜單,顯示彩色背景的“歡迎”信息。圖一顯示了程序剛啟動時的主窗口。

圖一:媒體播放器的主窗口

“文件”菜單包含三個菜單項。“打開”菜單顯示一個對話框,用來選擇媒體文件的位置。“循環”菜單決定媒體文件只播放一次(默認)還是反復播放(當菜單被選中)。最後,“退出”菜單關閉程序。另外,點擊主窗口右上角的關閉按鈕也可以關閉程序。請參見圖二。

圖二:“文件”菜單

點擊“文件/打開”菜單時,“打開媒體文件”對話框出現。選中媒體文件之後,點擊“打開”按鈕即可打開媒體文件;點擊“取消”按鈕中止文件打開操作。如圖三所示。

圖三:“打開媒體文件”對話框

除了上面提到的部件之外,媒體播放器還包含一個視覺部件、一個控制面板部件。視覺部件順序播放媒體文件包含的各幀圖像;控制面板部件允許用戶暫停、開始媒體文件的回放,或進行其他控制操作,例如查看媒體文件信息。

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”命令啟動媒體播放器。圖一顯示了媒體播放器剛啟動之後的界面,圖四是正在播放媒體的界面。

圖四:用媒體播放器回放MPG電影

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved