【问题标题】:JavaFX Media Player - Binding Progress bar with Media Player (Mac m1 Silicon)JavaFX 媒体播放器 - 将进度条与媒体播放器绑定(Mac m1 Silicon)
【发布时间】:2022-07-04 21:01:21
【问题描述】:

我想通过媒体播放器播放来更新进度条。但是,在开始播放我的进度条后,在一秒钟内填充 100%,而媒体为 15 秒 - 5 分钟。查不出原因。

我的代码如下:

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
        );
    }

还有 TimeElapsed 类:

static class TimeElapsed {
        private final double elapsed;

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

        public double getElapsed() {
            return elapsed;
        }
    }

那么,1) 使用 Playing 更新 progressBar,以及 2) 通过单击或拖动进度条来查找歌曲的代码更改是什么?

【问题讨论】:

  • 进度必须介于 0 和 1 之间,因此您需要经过的秒数除以媒体播放器的总秒数
  • 不要使用静态范围
  • @James_D,我试过了,但是每首歌曲的长度返回值都是一样的,并且该值不像歌曲长度那么合适,这意味着没有提供或允许实际长度值。

标签: macos javafx binding apple-m1


【解决方案1】:

ProgressBar 的进度在确定时应介于0.0 和1.0(包括)的值之间。这意味着您应该将当前时间除以总持续时间以获取进度并将进度条的进度属性绑定到该值。请注意,Media 的持续时间是可观察的,并且几乎可以保证在它被实例化之后的某个时间设置。

至于在进度条被点击或拖拽时是否能进行搜索,最简单的方法——也就是我在下面的例子中展示的——是在进度条上添加一个MOUSE_CLICKED和一个MOUSE_DRAGGED处理程序,确定鼠标的x 位置与条形宽度的比值,然后求计算出的时间。不幸的是,此设置可能与进度条的视觉效果不完全匹配,因为实际的“进度条”小于节点占用的整个空间(至少在默认样式下)。如果您想要“像素完美”的行为,您可能必须创建自己的控件。


这是一个演示上述内容的最小示例:

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());
  }
}

【讨论】:

  • 我得到每首歌的持续时间:9.739150367346899E7 ms。同时检查 System.out.println("Duration : "+duration);在您的代码中: var duration = player.getMedia().getDuration();所以,ProgressBar 什么也不显示。这是 Mac M1 (silicon) 的行为吗?我该怎么办?
  • 如果这些是您确定报告正确持续时间的媒体文件(例如,在其他应用程序或其他操作系统中),那么它可能是 JavaFX 的错误。我相信在首次添加支持时 M1 系统存在相当多的错误,因此首先确保您使用的是最新版本的 JavaFX(在撰写此评论时,最新版本是 18)。如果问题在最新版本上仍然存在,你可以创建一个minimal reproducible example来演示问题,那么我建议submitting a bug report。
  • 谢谢,我用的是最新版本,连平台都看上了。所以,我认为这是错误。但我不熟悉提交错误报告。无论如何,我会努力的,Insha Allah。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多