对于很多Java开发小伙伴来说,不少童鞋都了解过JavaFX,但介于JavaFX的局限性,可能大多数Java开发者也不是很了解,因而在JavaFX中自然也就缺乏实战经验,但是有时候呢我们也想自己研发一些小程序,比如说前面文章中给大家提到的 图片浏览器 ,或者说音频浏览器、视频浏览器等,那今天小编就带大家走进视频浏览器的编程过程!
效果图如下:
要求:
背景主色为黑色;
视频上下居中,左右居中,并保持界面中最大化显示;
进度条控制播放进度;
音频大小可拖动音频进度条控制;
默认打开即播放,点击画面暂停,继续单击又开始播放。
难点分析:
通过Media指定播放视频文件,通过MediaPlayer实现播放控制;
使用BorderPane布局方式让视频横向和纵向都居中;
使用Slider绑定播放进度条事件动态显示播放进度;
设置高度宽度改变事件来重置容器宽度和高度。
细节优化点:
当全屏播放时,显示退出全屏,并且不显示头部标题,退出全屏时操作相反;
视频播放时需要根据视频播放时长自动计算播放时长;
ESC退出全屏播放。
好啦,废话不多说,那我们接下来就用代码来实现看看效果吧。
代码如下:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
import javafx.util.Duration;
public class VideoPlayerApplication extends Application {
private Stage primaryStage;
private Label time = new Label();
private double allTime = 0;
private Slider playSlider;
private Slider audioSlider = new Slider(0, 100, 80);
private boolean isplay;
private Media media;
private MediaPlayer player;
private String title;
public VideoPlayerApplication() {
// 默认初始化标题及其文件URL
this.title = "测试";
this.media = new Media("http://192.168.18.9:8080/files/20230313/9c49403b-929b-4f65-843b-4c122432b90d.mp4");
}
public VideoPlayerApplication(String title, String url) {
this.media = new Media(url);
this.title = title;
}
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
player = new MediaPlayer(media);
player.play();
isplay = true;
MediaView mediaView = new MediaView(player);
VBox anchorPane = new VBox(mediaView);
anchorPane.setAlignment(Pos.CENTER);
anchorPane.setPrefWidth(800);
anchorPane.setPrefHeight(600);
anchorPane.setStyle("-fx-background-color: #000;");
BorderPane root = new BorderPane(anchorPane);
root.setPrefWidth(800);
root.setPrefHeight(600);
player.volumeProperty().bind(audioSlider.valueProperty().divide(100));
root.setOnMouseClicked(event -> {
playOrStop();
});
playSlider = new Slider();
playSlider.setMin(0);
playSlider.setMax(500);
playSlider.setPrefWidth(800);
playSlider.setValue(0);
VBox.setMargin(playSlider, new Insets(-50, 0, 0, 0));
anchorPane.getChildren().add(playSlider);
Label full = new Label("全屏");
full.setOnMouseClicked(event -> {
fullScreen(full);
});
Label label = new Label(">");
label.setTextAlignment(TextAlignment.CENTER);
label.setAlignment(Pos.CENTER);
label.setPrefWidth(650);
label.setMinWidth(80);
Label vol = new Label("音量");
vol.setStyle("-fx-text-fill:white");
audioSlider.setMaxWidth(80);
audioSlider.setMinWidth(30);
// audioSlider.setRotate(-90);
HBox hBox = new HBox(full, label, vol, audioSlider);
hBox.setPadding(new Insets(20, 0, 0, 0));
anchorPane.getChildren().add(hBox);
Scene scene = new Scene(root);
primaryStage.setTitle(title);
primaryStage.setScene(scene);
primaryStage.show();
player.currentTimeProperty().addListener((x, y, z) -> {
if (isplay) {
double currents = player.getCurrentTime().toSeconds();
allTime = player.getStopTime().toSeconds();
playSlider.setValue(currents / allTime * 500);
time.setText(formattime(currents, allTime, 0));
}
});
playSlider.setOnMousePressed(x -> {
isplay = false;
});
playSlider.setOnMouseReleased(x -> {
player.seek(Duration.seconds(playSlider.getValue() / 500 * allTime));
isplay = true;
});
ChangeListener<Number> changeListener = (event, oldVal, newVal) -> {
System.out.println("oldVal = " + oldVal + ", newVal = " + newVal);
mediaView.setFitHeight(primaryStage.getHeight() - 40);
mediaView.setFitWidth(primaryStage.getWidth());
};
primaryStage.widthProperty().addListener(changeListener);
primaryStage.heightProperty().addListener(changeListener);
primaryStage.fullScreenProperty().addListener((event, q, d) -> {
fullScreen(full);
});
root.setOnKeyPressed(event -> {
System.out.println(event.getCode());
if (KeyCode.SPACE.equals(event.getCode())) {
playOrStop();
}
});
primaryStage.setOnCloseRequest(event -> {
player.pause();
player.stop();
});
mediaView.setFitHeight(primaryStage.getHeight() - 40);
mediaView.setFitWidth(primaryStage.getWidth());
}
private void playOrStop() {
if (isplay) {
isplay = false;
player.pause();
} else {
Duration seconds = Duration.seconds(playSlider.getValue() / 500 * allTime);
player.seek(seconds);
isplay = true;
player.play();
}
}
private void fullScreen(Label full) {
if ("全屏".equals(full.getText())) {
primaryStage.setFullScreen(true);
audioSlider.setVisible(false);
playSlider.setVisible(false);
full.setText("退出全屏");
} else {
primaryStage.setFullScreen(false);
audioSlider.setVisible(true);
playSlider.setVisible(true);
full.setText("全屏");
}
}
public static String formattime(double this_time, double all_time, int type) {
String thistime = String.format("%02d:%02d:%02d", (int) this_time / 3600, (int) this_time % 3600 / 60, (int) this_time % 60);
String alltime = String.format("%02d:%02d:%02d", (int) all_time / 3600, (int) all_time % 3600 / 60, (int) all_time % 60);
return type == 1 ? thistime : type == 2 ? alltime : thistime + "/" + alltime;
}
}
有了这个基础,我们是不是可以自己做一个视频播放器呢,那答案一定是肯定的,但是如果是支持缩放,也就是说界面大小可以由用户自由缩放,这样的话处理起来会复杂的多,如果有想法的话,建议固定默认播放界面大小(但是全屏一定得支持,不然用户体验及其不友好),剩余的大家可以自由探索,如果是编程过程中有碰到问题的,随时可以私信我。
好啦,今天课程就到此结束,下课!