本文將引導您從零建立一個基於 Java Media Framework (JMF) 的媒體播放器,具備以下功能:
主視窗:標題「媒體播放器 1.0」,200x200 像素,藍色背景顯示歡迎訊息
選單列:檔案選單含三項 (開啟/循環/結束),循環項目為 CheckboxMenuItem
檔案對話框:模態對話框,記憶上次開啟目錄
播放元件:JMF Player 提供的 Visual Component (影像區) 與 Control Panel Component (控制列)
核心類別 MediaPlayer extends Frame 實作三大監聽器:
paint() 繪製歡迎畫面,update() 防止閃爍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(); }
public void windowClosed(WindowEvent e) {
if (player != null) player.close();
System.exit(0);
}
});
// 建立選單
Menu m = new Menu("檔案");
MenuItem open = new MenuItem("開啟"); open.addActionListener(this); m.add(open);
m.addSeparator();
CheckboxMenuItem loopItem = new CheckboxMenuItem("循環", false);
loopItem.addItemListener(this); m.add(loopItem);
m.addSeparator();
MenuItem exit = new MenuItem("結束"); exit.addActionListener(this); m.add(exit);
setMenuBar(new MenuBar()); getMenuBar().add(m);
setSize(200, 200); setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("結束")) { 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 (Exception ex) { System.out.println(ex); return; }
if (player == null) return;
first = false;
setTitle(fd.getFile());
player.addControllerListener(this);
player.prefetch();
}
public void controllerUpdate(ControllerEvent e) {
if (e instanceof ControllerClosedEvent) {
if (vc != null) { remove(vc); vc = null; }
if (cc != null) { remove(cc); cc = null; }
} else if (e instanceof EndOfMediaEvent) {
if (loop) { player.setMediaTime(new Time(0)); player.start(); }
} else if (e instanceof PrefetchCompleteEvent) {
player.start();
} else 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, 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 sw = fm.stringWidth("*** 歡迎 ***");
g.setColor(Color.white);
g.drawString("*** 歡迎 ***", (w - sw) / 2, (h + getInsets().top) / 2);
}
super.paint(g); // 確保控制面板正確繪製
}
public void update(Graphics g) { paint(g); } // 避免背景清除造成控制面板閃爍
public static void main(String[] args) { new MediaPlayer("媒體播放器 1.0"); }
}
sound.jar、jmf.jarjavac MediaPlayer.java (產生 MediaPlayer.class、MediaPlayer$1.class)java MediaPlayer| 技術點 | 說明 |
|---|---|
| JMF Player 生命週期 | Realizing → Prefetching → Started,各階段透過 ControllerEvent 通知 |
| 視覺/控制元件整合 | RealizeComplete 後取得元件並加入 Container,呼叫 pack() 調整視窗大小 |
| 循環播放實作 | EndOfMediaEvent 中重設 mediaTime 為 0 並再次 start() |
| 資源釋放 | ControllerClosedEvent 移除元件;windowClosed 呼叫 player.close() |
| 繪圖最佳化 | update() 直接呼叫 paint() 避免清除背景導致控制面板閃爍 |