Java写播放代码
本帖最后由 小九九 于 2024-7-2 16:58 编辑package com.example.window;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.Slider;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class VideoPlayerExample extends Application {
private Stage primaryStage;
private StackPane root;
private MediaPlayer mediaPlayer;
private ListView<String> playlist;
private boolean isPlaylistVisible = true;
private Button togglePlaylistButton;
private Button openFileButton;
private ScheduledExecutorService mouseIdleExecutor;
private boolean isMouseIdle = false;
// 提取文件名(不带扩展名)的方法
private static String extractFileNameWithoutExtension(String path) {
int lastSlashIndex = path.lastIndexOf('/');
if (lastSlashIndex == -1) {
lastSlashIndex = path.lastIndexOf('\\');
}
if (lastSlashIndex == -1) {
return path;
}
String fileName = path.substring(lastSlashIndex + 1);
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex == -1) {
return fileName;
}
return fileName.substring(0, lastDotIndex);
}
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
root = new StackPane();
double borderWidth = 1.0;
root.setStyle("-fx-background-color: black; -fx-border-color: black; -fx-border-width: " + borderWidth + "px;");
// 默认视频文件
File defaultFile = new File("G:/音乐.mp4");
if (defaultFile.exists()) {
Media media = new Media(defaultFile.toURI().toString());
mediaPlayer = new MediaPlayer(media);
} else {
mediaPlayer = new MediaPlayer(new Media("https://www.example.com/default_video.mp4")); // 默认视频URL
}
mediaPlayer.setAutoPlay(true);
MediaView mediaView = new MediaView(mediaPlayer);
StackPane.setAlignment(mediaView, Pos.CENTER);
mediaView.fitWidthProperty().bind(root.widthProperty().subtract(borderWidth * 2));
mediaView.fitHeightProperty().bind(root.heightProperty().subtract(borderWidth * 2));
// 播放列表
playlist = new ListView<>();
playlist.getItems().addAll(
"",
"节目 1",
"节目 2",
"节目 3",
"节目 4",
"节目 5",
"节目 6",
"节目 7",
"节目 8",
"节目 9",
"节目 10"
);
playlist.setPrefWidth(200);
playlist.setMaxWidth(200);
playlist.setMinWidth(200);
playlist.getSelectionModel().select(1);
playlist.getStyleClass().add("playlist");
// 播放列表显示/隐藏按钮
togglePlaylistButton = new Button("\u003C");
togglePlaylistButton.getStyleClass().add("togglePlaylistButton");
togglePlaylistButton.setOnAction(event -> {
isPlaylistVisible = !isPlaylistVisible;
playlist.setVisible(isPlaylistVisible);
openFileButton.setVisible(isPlaylistVisible);
if (isPlaylistVisible) {
togglePlaylistButton.setText("\u003C");
togglePlaylistButton.setTranslateX(0);
togglePlaylistButton.setVisible(true);
} else {
togglePlaylistButton.setText("\u003E");
togglePlaylistButton.setTranslateX(-200);
togglePlaylistButton.setVisible(false);
}
});
HBox playlistContainer = new HBox(playlist, togglePlaylistButton);
playlistContainer.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(playlist, javafx.scene.layout.Priority.ALWAYS);
// 监听媒体播放状态
mediaPlayer.statusProperty().addListener(new ChangeListener<MediaPlayer.Status>() {
@Override
public void changed(ObservableValue<? extends MediaPlayer.Status> observable, MediaPlayer.Status oldValue, MediaPlayer.Status newValue) {
if (newValue == MediaPlayer.Status.PLAYING) {
String currentMediaPath = mediaPlayer.getMedia().getSource();
String currentMediaName = extractFileNameWithoutExtension(currentMediaPath);
updatePlaylist(currentMediaName);
}
}
});
StackPane.setAlignment(playlistContainer, Pos.CENTER_LEFT);
root.getChildren().addAll(mediaView, playlistContainer);
// 打开文件按钮
openFileButton = new Button("文件");
openFileButton.getStyleClass().add("openFileButton");
openFileButton.setOnAction(event -> {
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().add(
new FileChooser.ExtensionFilter("视频文件", "*.mp4", "*.mkv", "*.avi")
);
File selectedFile = fileChooser.showOpenDialog(primaryStage);
if (selectedFile != null) {
Media newMedia = new Media(selectedFile.toURI().toString());
mediaPlayer.stop();
mediaPlayer.dispose();
mediaPlayer = new MediaPlayer(newMedia);
mediaPlayer.setAutoPlay(true);
mediaView.setMediaPlayer(mediaPlayer);
}
});
StackPane.setAlignment(openFileButton, Pos.TOP_LEFT);
root.getChildren().add(openFileButton);
// 进度条
Slider slider = new Slider();
slider.setMin(0);
slider.setMax(100);
slider.setValue(0);
slider.setShowTickLabels(false);
slider.setShowTickMarks(false);
slider.setMaxWidth(500);
StackPane.setAlignment(slider, Pos.BOTTOM_CENTER);
StackPane.setMargin(slider, new Insets(0, 0, 20, 0));
slider.valueProperty().addListener((observable, oldValue, newValue) -> {
double value = newValue.doubleValue();
double max = slider.getMax();
if (max != 0) { // 确保 max 不为 0,避免除以 0 的情况
double fraction = value / max;
if (!Double.isNaN(fraction)) { // 确保 fraction 不是 NaN
String color = String.format("-fx-background-color: linear-gradient(to right, #00ff00 %f%%, transparent %f%%);" +
"-fx-background-radius: 10px;", fraction * 100, fraction * 100);
slider.setStyle(color);
} else {
// 处理 fraction 为 NaN 的情况,例如设置一个默认样式
slider.setStyle("-fx-background-color: linear-gradient(to right, #00ff00 0%, transparent 0%);" +
"-fx-background-radius: 10px;");
}
} else {
// 处理 max 为 0 的情况,例如设置一个默认样式
slider.setStyle("-fx-background-color: linear-gradient(to right, #00ff00 0%, transparent 0%);" +
"-fx-background-radius: 10px;");
}
});
slider.setStyle("-fx-background-radius: 10px;");
root.getChildren().add(slider);
// 总时间标签
Label durationLabel = new Label("00:00");
durationLabel.getStyleClass().add("durationLabel");
durationLabel.setTextFill(javafx.scene.paint.Color.RED);
StackPane.setAlignment(durationLabel, Pos.BOTTOM_CENTER);
StackPane.setMargin(durationLabel, new Insets(0, 0, 18.0, 0));
durationLabel.translateXProperty().bind(slider.widthProperty().subtract(durationLabel.getWidth() / 2 + 135));
root.getChildren().add(durationLabel);
// 当前时间标签
Label currentTimeLabel = new Label("00:00:00");
currentTimeLabel.setTextFill(javafx.scene.paint.Color.WHITE);
currentTimeLabel.getStyleClass().add("currentTimeLabel");
StackPane.setAlignment(currentTimeLabel, Pos.BOTTOM_CENTER);
StackPane.setMargin(currentTimeLabel, new Insets(0, 0, 17.5, 0));
currentTimeLabel.translateXProperty().bind(slider.widthProperty().subtract(currentTimeLabel.getWidth() / 2 + 200));
root.getChildren().add(currentTimeLabel);
// 斜杠标签
Label slashLabel = new Label("/");
slashLabel.setTextFill(javafx.scene.paint.Color.WHITE);
slashLabel.getStyleClass().add("slashLabel");
StackPane.setAlignment(slashLabel, Pos.BOTTOM_CENTER);
StackPane.setMargin(slashLabel, new Insets(0, 0, 18.0, 0));
slashLabel.translateXProperty().bind(slider.widthProperty().subtract(slashLabel.getWidth() / 2 + 167.5));
root.getChildren().add(slashLabel);
// 播放/暂停按钮
Button playButton = new Button();
playButton.getStyleClass().add("playButton");
playButton.setOnAction(event -> {
if (mediaPlayer.getStatus() == MediaPlayer.Status.PLAYING) {
mediaPlayer.pause();
playButton.getStyleClass().remove("playButton");
playButton.getStyleClass().add("pauseButton");
} else {
mediaPlayer.play();
playButton.getStyleClass().remove("pauseButton");
playButton.getStyleClass().add("playButton");
}
});
StackPane.setAlignment(playButton, Pos.BOTTOM_CENTER);
StackPane.setMargin(playButton, new Insets(0, 0, 45, 0));
playButton.translateXProperty().bind(slider.widthProperty().subtract(playButton.getWidth() / 2 + 500));
root.getChildren().add(playButton);
// 设置视频总时间
mediaPlayer.setOnReady(() -> {
javafx.util.Duration totalDuration = mediaPlayer.getMedia().getDuration();
int hours = (int) (totalDuration.toHours());
int minutes = (int) (totalDuration.toMinutes() % 60);
int seconds = (int) (totalDuration.toSeconds() % 60);
durationLabel.setText(String.format("%d:%02d:%02d", hours, minutes, seconds));
});
// 视频结束时重置时间
mediaPlayer.setOnEndOfMedia(() -> {
durationLabel.setText("00:00:00");
});
// 更新当前播放时间
mediaPlayer.currentTimeProperty().addListener((observable, oldValue, newValue) -> {
javafx.util.Duration currentTime = newValue;
int hours = (int) (currentTime.toHours());
int minutes = (int) (currentTime.toMinutes() % 60);
int seconds = (int) (currentTime.toSeconds() % 60);
currentTimeLabel.setText(String.format("%d:%02d:%02d", hours, minutes, seconds));
});
final double THRESHOLD = 1;
slider.valueProperty().addListener((observable, oldValue, newValue) -> {
double value = newValue.doubleValue();
double oldVal = oldValue.doubleValue();
if (Math.abs(value - oldVal) >= THRESHOLD) {
double max = slider.getMax();
double fraction = value / max;
javafx.util.Duration totalDuration = mediaPlayer.getMedia().getDuration();
javafx.util.Duration newTime = new javafx.util.Duration(totalDuration.toMillis() * fraction);
mediaPlayer.seek(newTime);
}
});
mediaPlayer.currentTimeProperty().addListener((observable, oldValue, newValue) -> {
javafx.util.Duration currentTime = newValue;
javafx.util.Duration totalDuration = mediaPlayer.getMedia().getDuration();
double fraction = currentTime.toMillis() / totalDuration.toMillis();
slider.setValue(fraction * 100);
});
Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().add(getClass().getResource("/styles.css").toExternalForm());
scene.setOnMouseClicked(event -> {
if (event.getButton() == javafx.scene.input.MouseButton.PRIMARY && event.getClickCount() == 2) {
toggleFullScreen();
}
});
primaryStage.setScene(scene);
primaryStage.setTitle("视频播放器");
primaryStage.show();
scene.setOnMouseMoved(event -> {
resetMouseIdleTimer();
if (!isPlaylistVisible) {
togglePlaylistButton.setVisible(true);
}
});
scene.setOnMouseExited(event -> {
if (!isPlaylistVisible) {
togglePlaylistButton.setVisible(false);
}
});
initMouseIdleTimer();
scene.setOnMouseMoved(event -> resetMouseIdleTimer());
primaryStage.setScene(scene);
primaryStage.setTitle("视频播放器");
primaryStage.show();
}
// 初始化鼠标空闲计时器
private void initMouseIdleTimer() {
mouseIdleExecutor = Executors.newSingleThreadScheduledExecutor();
scheduleMouseIdleTask();
}
// 重置鼠标空闲计时器
private void resetMouseIdleTimer() {
if (isMouseIdle) {
Platform.runLater(() -> primaryStage.getScene().setCursor(javafx.scene.Cursor.DEFAULT));
}
isMouseIdle = false;
mouseIdleExecutor.shutdownNow();
mouseIdleExecutor = Executors.newSingleThreadScheduledExecutor();
scheduleMouseIdleTask();
if (!isPlaylistVisible) {
togglePlaylistButton.setVisible(true);
}
}
// 调度鼠标空闲任务
private void scheduleMouseIdleTask() {
mouseIdleExecutor.schedule(() -> {
isMouseIdle = true;
if (!isPlaylistVisible && togglePlaylistButton.getText().equals("\u003E")) {
togglePlaylistButton.setVisible(false);
}
Platform.runLater(() -> primaryStage.getScene().setCursor(javafx.scene.Cursor.NONE));
}, 5000, TimeUnit.MILLISECONDS);
}
// 更新播放列表
private void updatePlaylist(String currentMediaName) {
playlist.getItems().set(1, "正在播放: " + currentMediaName);
}
// 切换全屏
private void toggleFullScreen() {
primaryStage.setFullScreen(!primaryStage.isFullScreen());
}
public static void main(String[] args) {
launch(args);
}
}.playlist {
-fx-background-color: rgba(0, 0, 0, 0.5); /* 设置背景颜色为半透明黑色 */
-fx-text-fill: white;/* 设置文本颜色为白色 */
-fx-control-inner-background: rgba(0, 0, 0, 0.5);/* 设置内部背景颜色为半透明黑色 */
-fx-selection-bar: rgba(255, 255, 255, 0.3);/* 设置选择栏的颜色为半透明白色 */
-fx-selection-bar-text: white; /* 设置选择栏文本颜色为白色 */
}
.playlist .list-cell {
-fx-font-size: 14px; /* 初始字体大小 */
}
.openFileButton {
-fx-background-color: transparent;/* 设置背景颜色为透明 */
-fx-text-fill: white; /* 设置文本颜色为白色 */
-fx-font-size: 14px;/* 设置字体大小为 14 像素 */
-fx-font-weight: bold; /* 设置字体加粗 */
}
.togglePlaylistButton {
-fx-background-color: transparent;/* 设置背景颜色为透明 */
-fx-text-fill: white; /* 设置文本颜色为白色 */
-fx-font-size: 20px;/* 设置字体大小为 20 像素 */
-fx-font-weight: bold; /* 设置字体加粗 */
-fx-border-color: white;/* 设置边框颜色为白色 */
-fx-border-width: 2px;/* 设置边框宽度为 2 像素 */
-fx-border-radius: 50%;/* 设置边框圆角为 50% 以实现圆形 */
-fx-background-radius: 50%;/* 设置背景圆角为 50% 以实现圆形 */
-fx-padding: 5px;/* 设置内边距为 5 像素 */
}
.durationLabel {
-fx-text-fill: white; /* 设置文本颜色为白色 */
-fx-font-size: 14px; /* 设置字体大小为 14 像素 */
-fx-font-weight: bold;/* 设置字体加粗 */
}
.currentTimeLabel {
-fx-text-fill: white; /* 设置文本颜色为白色 */
-fx-font-size: 14px; /* 设置字体大小为 14 像素 */
-fx-font-weight: bold;/* 设置字体加粗 */
}
.slashLabel {
-fx-text-fill: white; /* 设置文本颜色为白色 */
-fx-font-size: 14px; /* 设置字体大小为 14 像素 */
-fx-font-weight: bold;/* 设置字体加粗 */
}
.playButton {
-fx-background-color: transparent;/* 设置背景颜色为透明 */
-fx-text-fill: white; /* 设置文本颜色为白色 */
-fx-font-size: 16px;/* 设置字体大小为 16 像素 */
-fx-font-weight: bold; /* 设置字体加粗 */
-fx-border-color: white;/* 设置边框颜色为白色 */
-fx-border-width: 2px;/* 设置边框宽度为 2 像素 */
-fx-padding: 3px;/* 设置内边距为 3 像素 */
-fx-min-width: 25px;/* 设置最小宽度为 25 像素 */
-fx-max-width: 25px;/* 设置最大宽度为 25 像素 */
-fx-shape: "M 50,25 L 75,50 L 50,75 z";/* 设置形状为向右三角形 */
}
.pauseButton {
-fx-background-color: transparent;/* 设置背景颜色为透明 */
-fx-text-fill: white; /* 设置文本颜色为白色 */
-fx-font-size: 16px;/* 设置字体大小为 16 像素 */
-fx-font-weight: bold; /* 设置字体加粗 */
-fx-border-color: white;/* 设置边框颜色为白色 */
-fx-border-width: 2px;/* 设置边框宽度为 2 像素 */
-fx-padding: 3px;/* 设置内边距为 3 像素 */
-fx-min-width: 25px;/* 设置最小宽度为 25 像素 */
-fx-max-width: 25px;/* 设置最大宽度为 25 像素 */
-fx-shape: "M 40,25 L 50,25 L 50,75 L 40,75 z M 60,25 L 70,25 L 70,75 L 60,75 z";/* 设置形状为两条竖线 */
}
页:
[1]