3

我有一个名为TimeElapsed(不可变的)的自定义类。TimeElapsed有一个接受 a 的构造函数Duration(这是 JavaFxMediaPlayer中用于跟踪时间的类型)。然后构造函数将 转换DurationTimeElapsed

问题是我有一个需要返回TimeElapsed ObservableValue. 我需要的是能够做这样的事情:

new Binding<TimeElapsed>() {

     {
          super.bind(player.duration())
     }

     @Override
     protected TimeElapsed computeValue() {
          return new TimeElapsed(player.duration());
     }
}

但是由于某种原因,没有Binding泛型,您只能使用DoubleBinding类似的方法来执行此操作,您可以在其中计算值但无法选择类型。所以我该怎么做?

4

1 回答 1

7

使用ObjectBinding<TimeElapsed>.

关键方法

/* @return an ObjectBinding of immutable TimeElapsed objects for the player */
private ObjectBinding<TimeElapsed> createElapsedBindingByBindingsAPI(
        final MediaPlayer player
    ) {
    return Bindings.createObjectBinding(
        new Callable<TimeElapsed>() {
            @Override
            public TimeElapsed call() throws Exception {
                return new TimeElapsed(player.getCurrentTime());
            }
        },
        player.currentTimeProperty()
    );
}

完整的可执行示例

更改MEDIA_PATH示例中的 以匹配您所需的媒体。

import javafx.application.Application;
import javafx.beans.binding.*;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.media.*;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.File;
import java.net.MalformedURLException;
import java.util.concurrent.Callable;

/** Displays progress (time elapsed in seconds) of playing a media file. */    
public class TimeElapsedBinding extends Application {
    private static final String MEDIA_PATH = 
        "C:\\Users\\Public\\Music\\Sample Music\\Dillon - Thirteen Thirtyfive.mp3";

    public static void main(String[] args) { launch(args); }

    @Override public void start(Stage stage) throws Exception {
        final MediaView   mediaView    = createMediaView();
        final MediaPlayer player       = mediaView.getMediaPlayer();
        final Label       elapsedLabel = new Label();

        ObjectBinding<TimeElapsed> elapsedBinding =
            createElapsedBindingByBindingsAPI(player);
        StringBinding elapsedStringBinding =
            createStringBindingByBindingsAPI(elapsedBinding);

        elapsedLabel.textProperty().bind(
                elapsedStringBinding
        );

        StackPane layout = new StackPane();
        layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 20px;");
        layout.getChildren().setAll(
                mediaView,
                elapsedLabel
        );

        stage.setScene(new Scene(layout));
        stage.show();
    }

    /* @return an ObjectBinding of immutable TimeElapsed objects for the player */
    private ObjectBinding<TimeElapsed> createElapsedBindingByBindingsAPI(
            final MediaPlayer player
        ) {
        return Bindings.createObjectBinding(
            new Callable<TimeElapsed>() {
                @Override
                public TimeElapsed call() throws Exception {
                    return new TimeElapsed(player.getCurrentTime());
                }
            },
            player.currentTimeProperty()
        );
    }

    /* @return a string binding to an ObjectBinding of immutable TimeElapsed objects */
    private StringBinding createStringBindingByBindingsAPI(
            final ObjectBinding<TimeElapsed> elapsedBinding
        ) {
        return Bindings.createStringBinding(
                new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        return String.format(
                                "%.0f",
                                elapsedBinding.getValue().getElapsed()
                        );
                    }
                },
                elapsedBinding
        );
    }

    /* @Return a new MediaView from a predefined MEDIA_PATH string */
    private MediaView createMediaView() throws MalformedURLException {
        String mediaURI = new File(MEDIA_PATH).toURI().toURL().toExternalForm();

        Media media = new Media(mediaURI);
        MediaPlayer player = new MediaPlayer(media);
        MediaView mediaView = new MediaView(player);
        player.play();

        return mediaView;
    }

    /** immutable TimeElapsed class. */
    class TimeElapsed {
        private final double elapsed;

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

        public double getElapsed() {
            return elapsed;
        }
    }
}

以上仅作为示例提供,以适应在 ObjectBinding 中使用不可变对象的问题框架,而不是作为跟踪播放媒体进度的最有效方法。

替代实施

如果不需要在 ObjectBinding 中使用不可变对象,我将直接监视 MediaPlayer 的进度属性,类似于下面的代码:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.scene.media.*;
import javafx.stage.Stage;

import java.io.File;
import java.net.MalformedURLException;

public class MediaProgressMonitoring extends Application {
    private static final String MEDIA_PATH = "C:\\Users\\Public\\Music\\Sample Music\\Dillon - Thirteen Thirtyfive.mp3";

    public static void main(String[] args) { launch(args); }

    @Override public void start(Stage stage) throws Exception {
        final MediaView   mediaView = createMediaView();
        final MediaPlayer player    = mediaView.getMediaPlayer();
        final ProgressBar progress  = new ProgressBar(0);
        progress.setPrefWidth(800);

        player.currentTimeProperty().addListener((observable) ->
            progress.setProgress(
                player.getCurrentTime().toMillis() / 
                player.getTotalDuration().toMillis()
            )
        );

        StackPane layout = new StackPane();
        layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 20px;");
        layout.getChildren().setAll(
                mediaView,
                progress
        );

        stage.setScene(new Scene(layout));
        stage.show();
    }

    private MediaView createMediaView() throws MalformedURLException {
        String mediaURI = new File(MEDIA_PATH).toURI().toURL().toExternalForm();

        Media media = new Media(mediaURI);
        MediaPlayer player = new MediaPlayer(media);
        MediaView mediaView = new MediaView(player);
        player.play();

        return mediaView;
    }
}
于 2013-08-14T19:10:20.517 回答