JavaFX多媒體(2)使用Media播放音訊與影像
|
JavaFX多媒體(1)使用Audio Clip播放音訊 << 前情 在前一篇當中,我們介紹如何以JavaFX的AudioClip類別播放簡短音訊,AudioClip類別的主要功能僅在於播放與停止播放音訊,並無法處理暫停播放、音訊時間長度、後設資料、等化器、事件等功能。 除了AudioClip類別之外,欲播放音訊與影像媒體,可使用以下類別處理:
其中Media類別用以設定音訊與影像來源,可為URL或本機檔案。此外,Media類別並處理音訊與影像的時間長度、後設資料、標記等資訊。 待Media類別設定音訊與影像來源之後,則交由MediaPlayer類別處理,如同其名稱Media Player (媒體播放器) 一般,用以播放、暫停、重覆或停止播放媒體,並處理調整音量平衡、重覆播放次數、播放速率、音量大小、時間長度、頻譜等資訊。 MediaView類別如同TableView、TreeView與WebView一般,用以「顯示」影像媒體。在實作上,若處理音訊,僅需使用Media與MediaPlayer類別;若處理影像,則需以Media、MediaPlayer與MediaView類別三者搭配一起使用。 請參考以下範例,分別以Media與MediaPlayer類別播放音訊,首先以Media類別設定音訊來源,可為URL或本機檔案,接著以MediaPlayer類別的setAutoPlay()方法自動播放音訊: Media media;
MediaPlayer mediaplayer;
...
try {
String directory = System.getProperty("user.dir");
File file = new File(directory, "../../media/Audio.mp3");
media = new Media(file.toURI().toString());
mediaplayer = new MediaPlayer(media);
// 自動播放音訊
mediaplayer.setAutoPlay(true);
}
catch (Exception ex) {
ex.toString();
}
請參考以下範例,分別以Media、MediaPlayer與MediaView類別播放影像,首先以Media類別設定影像來源,可為URL或本機檔案,接著以MediaPlayer類別建立MediaPlayer物件,並由MediaView類別「顯示」影像媒體,最後再以MediaPlayer類別的play()方法播放影像: Media media;
MediaPlayer mediaplayer;
MediaView mediaview;
...
try {
String directory = System.getProperty("user.dir");
File file = new File(directory, "../../media/Video.mp4");
media = new Media(file.toURI().toString());
mediaplayer = new MediaPlayer(media);
mediaview = new MediaView(mediaplayer);
}
catch (Exception ex) {
ex.toString();
}
...
BorderPane borderpane = new BorderPane();
borderpane.setCenter(mediaview);
...
// 播放影像
mediaplayer.play();
為免影像因尺寸太大而超出視窗範圍,因此以MediaView類別的setFitHeight()與setFitWidth()方法分別設定影像的適合 (Fit) 高度與寬度,以便讓影像符合視窗範圍。 此外,並以heightProperty().addListener()與widthProperty().addListener()方法分別處理視窗高度與寬度的改變事件,當視窗高度或寬度改變時,同時調整影像的高度或寬度: mediaview.setFitHeight(primaryStage.getHeight());
mediaview.setFitWidth(primaryStage.getWidth());
primaryStage.heightProperty().addListener(new ChangeListener() {
@Override public void changed(ObservableValue observable,
Number oldValue, Number newValue) {
mediaview.setFitHeight((Double)newValue);
}
});
primaryStage.widthProperty().addListener(new ChangeListener() {
@Override public void changed(ObservableValue observable,
Number oldValue, Number newValue) {
mediaview.setFitWidth((Double)newValue);
}
});
請參考以下範例,範例加入標籤與滑動軸處理音訊,前者處理播放、暫停、向前與倒轉,後者調整時間長度、音量大小與音量平衡。 以播放與暫停為例,當點選播放標籤時,首先以MediaPlayer類別的getStatus()方法取得媒體目前的狀態,其回傳值分別為:
若狀態為正在播放時 (MediaPlayer.Status.PLAYING),則以MediaPlayer類別的pause()方法暫停播放;反之則以play()方法播放音訊: Label lblPlay = new Label("");
...
lblPlay.setOnMouseClicked(new EventHandler() {
@Override public void handle(MouseEvent e) {
// 取得媒體目前的狀態
if (mediaplayer.getStatus() == MediaPlayer.Status.PLAYING) {
// 暫停播放
mediaplayer.pause();
}
else {
// 播放音訊
mediaplayer.play();
}
}
});
以向前播放 (Forward) 為例,當點選向前標籤時,首先以MediaPlayer類別的getTotalDuration()方法取得音訊的總時間,接著以seek()方法移至音訊的最後,並藉此調整滑動軸的位置: Label lblForward = new Label("");
...
lblForward.setOnMouseClicked(new EventHandler() {
@Override public void handle(MouseEvent e) {
// 取得音訊的總時間
final Duration totalDuration = mediaplayer.getTotalDuration();
// 取得音訊目前的狀態
if (mediaplayer.getStatus() == MediaPlayer.Status.STOPPED) {
mediaplayer.pause();
}
// 移至音訊的最後
mediaplayer.seek(totalDuration);
// 取得音訊目前的狀態
if (mediaplayer.getStatus() != MediaPlayer.Status.PLAYING) {
if (sliderDuration.isValueChanging())
return;
final Duration total = mediaplayer.getTotalDuration();
if (total == null || totalDuration == null) {
// 調整滑動軸的位置
sliderDuration.setValue(0);
}
else {
// 調整滑動軸的位置
sliderDuration.setValue(
totalDuration.toMillis() / total.toMillis());
}
}
}
});
倒轉播放 (Rewind) 類似於向前播放,差別僅在於當點選倒轉標籤時,首先將音訊的目前進度時間設為Duration.ZERO (歸零),接著以seek()方法移至音訊的最前端,並藉此調整滑動軸的位置: Label lblRewind = new Label("");
...
lblRewind.setOnMouseClicked(new EventHandler() {
@Override public void handle(MouseEvent e) {
// 設定目前的進度時間為零
final Duration currentduration = Duration.ZERO;
// 取得音訊目前的狀態
if (mediaplayer.getStatus() == MediaPlayer.Status.STOPPED) {
mediaplayer.pause();
}
// 移至音訊的最前端
mediaplayer.seek(currentduration);
// 取得音訊目前的狀態
if (mediaplayer.getStatus() != MediaPlayer.Status.PLAYING) {
if (sliderDuration.isValueChanging())
return;
final Duration total = mediaplayer.getTotalDuration();
if (total == null) {
// 調整滑動軸的位置
sliderDuration.setValue(0);
}
else {
// 調整滑動軸的位置
sliderDuration.setValue(
currentduration.toMillis() / total.toMillis());
}
}
}
});
以滑動軸調整音量大小 (Volume) 為例,首先以Slider類別的valueProperty()方法取得滑動軸的值屬性,接著以bindBidirectional()方法與MediaPlayer類別的volumeProperty()建立雙向繫結 (Bidirectional Binding),當移動滑動軸時,則以滑動軸的值設定音訊的音量大小: Slider sliderVolume = new Slider(); sliderVolume.setMin(0.0); sliderVolume.setMax(1.0); sliderVolume.setValue(1.0); sliderVolume.setPrefWidth(60); sliderVolume.setMaxWidth(Region.USE_PREF_SIZE); sliderVolume.setMinWidth(30); // 建立滑動軸與音訊音量的雙向繫結 sliderVolume.valueProperty().bindBidirectional(mediaplayer.volumeProperty()); 以滑動軸調整音量平衡 (Balance) 為例,首先以Slider類別的valueProperty()方法取得滑動軸的值屬性,接著以addListener()方法處理滑動軸事件,當移動滑動軸時,則以滑動軸的值設定音訊的音量平衡: final Slider sliderBalance = new Slider();
sliderBalance.setMin(-1.0);
sliderBalance.setMax(1.0);
sliderBalance.setValue(0.0);
sliderBalance.setPrefWidth(60);
sliderBalance.setMaxWidth(Region.USE_PREF_SIZE);
sliderBalance.setMinWidth(30);
sliderBalance.valueProperty().addListener(new InvalidationListener() {
@Override public void invalidated(Observable observable) {
if (sliderBalance.isValueChanging()) {
// 設定音訊的音量平衡
mediaplayer.setBalance(sliderBalance.getValue());
}
}
});
【執行結果】 請參考以下範例,加入標籤與滑動軸處理影像,前者處理播放、暫停、向前與倒轉,後者調整時間長度、音量大小與音量平衡,程式與前述範例幾乎一樣,差別僅在於,以MediaPlayer類別所建立MediaPlayer物件,需由MediaView類別「顯示」影像媒體。 【執行結果】 【參考資料】 [1] Java Official Web Site |

Java 學習之路


