Javafx Media Player-与媒体播放器(MAC M1硅)绑定进度栏

发布于 2025-01-17 20:31:21 字数 1842 浏览 0 评论 0原文

我想通过媒体播放器更新进度栏。但是,在媒体为15秒-5分钟的时间内,一秒钟内开始演奏我的Progressbar 100%填充了100%。我不知道原因。

我的代码如下:

public static ProgressBar progress = new ProgressBar();

ObjectBinding<TimeElapsed> elapsedBinding =createElapsedBindingByBindingsAPI(player);
DoubleBinding elapsedDoubleBinding =createDoubleBindingByBindingsAPI(elapsedBinding);

progress.progressProperty().bind(elapsedDoubleBinding);

方法是:

    public static @NotNull ObjectBinding<TimeElapsed> createElapsedBindingByBindingsAPI(
            final @NotNull MediaPlayer player
    ) {
        return Bindings.createObjectBinding(
                new Callable<TimeElapsed>() {
                    @Override
                    public TimeElapsed call() throws Exception {
                        return new TimeElapsed(player.getCurrentTime());
                    }
                },
                player.currentTimeProperty()
        );
    }



public static @NotNull DoubleBinding createDoubleBindingByBindingsAPI(
            final ObjectBinding<TimeElapsed> elapsedBinding
    ) {
        return Bindings.createDoubleBinding(
                new Callable<Double>() {
                    @Override
                    public Double call() throws Exception {

                        
                        return  elapsedBinding.getValue().getElapsed();

                    }
                },
                elapsedBinding
        );
    }

和时间列出的类:

static class TimeElapsed {
        private final double elapsed;

        TimeElapsed(@NotNull Duration duration) {
          
            elapsed = duration.toSeconds();
        }

        public double getElapsed() {
            return elapsed;
        }
    }

那么,代码更改的代码是什么,1)通过播放更新进度键,而2)则单击或拖动进度栏,搜索歌曲?

I want to update Progress Bar with Media Player Playing. But, after start playing my progressBar fill 100% within one second while the media is 15 seconds - 5 minutes long. I can't figure out the cause.

My codes are as follows:

public static ProgressBar progress = new ProgressBar();

ObjectBinding<TimeElapsed> elapsedBinding =createElapsedBindingByBindingsAPI(player);
DoubleBinding elapsedDoubleBinding =createDoubleBindingByBindingsAPI(elapsedBinding);

progress.progressProperty().bind(elapsedDoubleBinding);

And The methods are :

    public static @NotNull ObjectBinding<TimeElapsed> createElapsedBindingByBindingsAPI(
            final @NotNull MediaPlayer player
    ) {
        return Bindings.createObjectBinding(
                new Callable<TimeElapsed>() {
                    @Override
                    public TimeElapsed call() throws Exception {
                        return new TimeElapsed(player.getCurrentTime());
                    }
                },
                player.currentTimeProperty()
        );
    }



public static @NotNull DoubleBinding createDoubleBindingByBindingsAPI(
            final ObjectBinding<TimeElapsed> elapsedBinding
    ) {
        return Bindings.createDoubleBinding(
                new Callable<Double>() {
                    @Override
                    public Double call() throws Exception {

                        
                        return  elapsedBinding.getValue().getElapsed();

                    }
                },
                elapsedBinding
        );
    }

And the TimeElapsed class :

static class TimeElapsed {
        private final double elapsed;

        TimeElapsed(@NotNull Duration duration) {
          
            elapsed = duration.toSeconds();
        }

        public double getElapsed() {
            return elapsed;
        }
    }

So, what's the code changes that 1) update the progressBar with Playing, and 2) seek the song with progress bar clicked or dragged?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黑寡妇 2025-01-24 20:31:21

当确定0.01.0(包含)的值之间,A 的进度应该是。这意味着您应该将当前时间除以总持续时间,以获得进度并将栏的进度属性绑定到该值。请注意,媒体的持续时间是可观察到的,并且几乎可以保证将其实例化之后设置为

至于能够在单击或拖动进度栏时寻找最简单的方法(这是我在下面的示例中显示的方法)是添加mouse_clicked >处理程序与进度栏,确定鼠标的x位置与条的宽度之间的比率,然后查找计算的时间。不幸的是,此设置可能与进度栏的视觉效果不完全匹配,因为实际的“ bar”小于节点所占用的整个空间(至少使用默认样式)。如果您想要“ Pixel Perfect”行为,则可能必须创建自己的控制。


这是一个最小的例子,证明了上述内容:

import java.util.Optional;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.input.MouseEvent;
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 javafx.util.Duration;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) {
    var mediaView = new MediaView();

    var progressBar = new ProgressBar();
    progressBar.setMaxWidth(Double.MAX_VALUE);
    StackPane.setAlignment(progressBar, Pos.BOTTOM_CENTER);
    StackPane.setMargin(progressBar, new Insets(10));

    var root = new StackPane(mediaView, progressBar);
    primaryStage.setScene(new Scene(root, 1000, 650));
    primaryStage.setTitle("Video Progress Demo");
    primaryStage.show();

    chooseMediaFile(primaryStage)
        .ifPresentOrElse(
            uri -> {
              var media = new Media(uri);
              var mediaPlayer = new MediaPlayer(media);
              mediaPlayer.setAutoPlay(true);
              mediaView.setMediaPlayer(mediaPlayer);

              bindProgress(mediaPlayer, progressBar);
              addSeekBehavior(mediaPlayer, progressBar);
            },
            Platform::exit);
  }

  private void bindProgress(MediaPlayer player, ProgressBar bar) {
    var binding =
        Bindings.createDoubleBinding(
            () -> {
              var currentTime = player.getCurrentTime();
              var duration = player.getMedia().getDuration();
              if (isValidDuration(currentTime) && isValidDuration(duration)) {
                return currentTime.toMillis() / duration.toMillis();
              }
              return ProgressBar.INDETERMINATE_PROGRESS;
            },
            player.currentTimeProperty(),
            player.getMedia().durationProperty());
    bar.progressProperty().bind(binding);
  }

  private void addSeekBehavior(MediaPlayer player, ProgressBar bar) {
    EventHandler<MouseEvent> onClickAndOnDragHandler =
        e -> {
          var duration = player.getMedia().getDuration();
          if (isValidDuration(duration)) {
            var seekTime = duration.multiply(e.getX() / bar.getWidth());
            player.seek(seekTime);
            e.consume();
          }
        };
    bar.addEventHandler(MouseEvent.MOUSE_CLICKED, onClickAndOnDragHandler);
    bar.addEventHandler(MouseEvent.MOUSE_DRAGGED, onClickAndOnDragHandler);
  }

  private boolean isValidDuration(Duration d) {
    return d != null && !d.isIndefinite() && !d.isUnknown();
  }

  private Optional<String> chooseMediaFile(Stage owner) {
    var chooser = new FileChooser();
    chooser
        .getExtensionFilters()
        .add(new FileChooser.ExtensionFilter("Media Files", "*.mp4", "*.mp3", "*.wav"));
    var file = chooser.showOpenDialog(owner);
    return Optional.ofNullable(file).map(f -> f.toPath().toUri().toString());
  }
}

The progress of a ProgressBar should be, when determinate, between the values of 0.0 and 1.0 (inclusive). This means you should be dividing the current time by the total duration to get the progress and bind the progress property of the bar to that value. Note that the duration of a Media is observable and is pretty much guaranteed to be set some time after it was instantiated.

As for being able to seek when the progress bar is clicked or dragged, the simplest way—which is what I show in the example below—is to add a MOUSE_CLICKED and a MOUSE_DRAGGED handler to the progress bar, determine the ratio between the mouse's x position and the bar's width, and then seek the calculated time. Unfortunately, this setup may not exactly match up with the visuals of the progress bar because the actual "bar" is smaller than the entire space taken up by the node (at least with default styling). You would probably have to create your own control if you want "pixel perfect" behavior.


Here is a minimal example demonstrating what's discussed above:

import java.util.Optional;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.input.MouseEvent;
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 javafx.util.Duration;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) {
    var mediaView = new MediaView();

    var progressBar = new ProgressBar();
    progressBar.setMaxWidth(Double.MAX_VALUE);
    StackPane.setAlignment(progressBar, Pos.BOTTOM_CENTER);
    StackPane.setMargin(progressBar, new Insets(10));

    var root = new StackPane(mediaView, progressBar);
    primaryStage.setScene(new Scene(root, 1000, 650));
    primaryStage.setTitle("Video Progress Demo");
    primaryStage.show();

    chooseMediaFile(primaryStage)
        .ifPresentOrElse(
            uri -> {
              var media = new Media(uri);
              var mediaPlayer = new MediaPlayer(media);
              mediaPlayer.setAutoPlay(true);
              mediaView.setMediaPlayer(mediaPlayer);

              bindProgress(mediaPlayer, progressBar);
              addSeekBehavior(mediaPlayer, progressBar);
            },
            Platform::exit);
  }

  private void bindProgress(MediaPlayer player, ProgressBar bar) {
    var binding =
        Bindings.createDoubleBinding(
            () -> {
              var currentTime = player.getCurrentTime();
              var duration = player.getMedia().getDuration();
              if (isValidDuration(currentTime) && isValidDuration(duration)) {
                return currentTime.toMillis() / duration.toMillis();
              }
              return ProgressBar.INDETERMINATE_PROGRESS;
            },
            player.currentTimeProperty(),
            player.getMedia().durationProperty());
    bar.progressProperty().bind(binding);
  }

  private void addSeekBehavior(MediaPlayer player, ProgressBar bar) {
    EventHandler<MouseEvent> onClickAndOnDragHandler =
        e -> {
          var duration = player.getMedia().getDuration();
          if (isValidDuration(duration)) {
            var seekTime = duration.multiply(e.getX() / bar.getWidth());
            player.seek(seekTime);
            e.consume();
          }
        };
    bar.addEventHandler(MouseEvent.MOUSE_CLICKED, onClickAndOnDragHandler);
    bar.addEventHandler(MouseEvent.MOUSE_DRAGGED, onClickAndOnDragHandler);
  }

  private boolean isValidDuration(Duration d) {
    return d != null && !d.isIndefinite() && !d.isUnknown();
  }

  private Optional<String> chooseMediaFile(Stage owner) {
    var chooser = new FileChooser();
    chooser
        .getExtensionFilters()
        .add(new FileChooser.ExtensionFilter("Media Files", "*.mp4", "*.mp3", "*.wav"));
    var file = chooser.showOpenDialog(owner);
    return Optional.ofNullable(file).map(f -> f.toPath().toUri().toString());
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文