ドキュメント



JavaFX: JavaFXアプリケーションへのメディア・アセットの組込み

3 メディア再生の制御

この項では、再生を制御するグラフィカルUI要素を備えたフル機能のメディア・プレーヤを作成します。

メディア・プレーヤを作成するには、次の図3-1に示すように、3つのネストされたメディア・オブジェクトの構造を実装し、グラフィカル・コントロールをエンコードし、再生機能に関するいくつかのロジックを追加する必要があります。

図3-1 再生コントロールのあるメディア・プレーヤの構造

UIコントロールのあるメディア・プレーヤの論理構造。
「図3-1 再生コントロールのあるメディア・プレーヤの構造」の説明

ここでは、第2章「Webページへのメディアの埋込み」で作成したメディア・プレーヤに再生コントロールを追加します。まだ完成していない場合は、この章のこれ以降に進む前に、そのメディア・プレーヤ・アプリケーションを完成する必要があります。追加するメディア・コントロール・パネルは、playButton、progressおよびvolumeControlの3つの要素で構成されます。

コントロールの作成

この項では、再生/一時停止、経過時間および音量機能のペインとUIコントロールを含む、新しいJavaFXソース・ファイルMediaControl.javaを作成します。

  1. NetBeans IDEでメイン・プロジェクトとしてEmbeddedMediaPlayerを開き、プロジェクトに追加する新しいJavaFXファイルを作成します。

    1. [Ctrl]キーを押しながら[N]キーを押すか、IDEのメイン・メニューから「ファイル」→「新規ファイル」を選択します。

    2. 「カテゴリ」で「JavaFX」、「ファイル・タイプ」で「JavaFXメイン・クラス」を選択します。「次」をクリックします。

    3. 「名前と場所」ダイアログで、「クラス名」フィールドにMediaControlと入力します。

    4. 「パッケージ」フィールドで、ドロップダウン・リストからembeddedmediaplayerを選択し、「終了」をクリックします。

  2. MediaControl.javaソース・ファイルで、package embeddedmediaplayer行より後のすべての行を削除します。

  3. 例3-1に示されているインポート文をファイルの先頭に追加します。

    例3-1 追加するインポート文

    import javafx.scene.control.Label;
    import javafx.scene.control.Slider;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.HBox;
    import javafx.scene.layout.Pane;
    import javafx.scene.media.MediaPlayer;
    import javafx.scene.media.MediaView;
    import javafx.util.Duration;
    
  4. 例3-2に示されているコード行をコピーして貼り付け、コントロールを含めるBorderPaneを作成します。

    例3-2 MediaControlクラス・コードの追加

    public class MediaControl extends BorderPane {
        private MediaPlayer mp;
        private MediaView mediaView;
        private final boolean repeat = false;
        private boolean stopRequested = false;
        private boolean atEndOfMedia = false;
        private Duration duration;
        private Slider timeSlider;
        private Label playTime;
        private Slider volumeSlider;
        private HBox mediaBar;
    
        public MediaControl(final MediaPlayer mp) {
            this.mp = mp;
            setStyle("-fx-background-color: #bfc2c7;");
            mediaView = new MediaView(mp);
            Pane mvPane = new Pane() {                };
            mvPane.getChildren().add(mediaView);
            mvPane.setStyle("-fx-background-color: black;"); 
            setCenter(mvPane);
         }
    }
    
  5. 例3-3のコード行をコピーして、setCenter(mvPane)という行の直後に貼り付けます。このコードにより、「Media」ツールバーと「Play」ボタンが追加されます。

    例3-3 「Media」ツールバーと「Play」ボタンの追加

    mediaBar = new HBox();
            mediaBar.setAlignment(Pos.CENTER);
            mediaBar.setPadding(new Insets(5, 10, 5, 10));
            BorderPane.setAlignment(mediaBar, Pos.CENTER);
     
            final Button playButton  = new Button(">");
            mediaBar.getChildren().add(playButton);
            setBottom(mediaBar); 
         }
    }
    
  6. 例3-4に示されているインポート文を、インポート文のリストの先頭に追加します。

    例3-4 さらなるインポート文の追加

    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.control.Button;
    
  7. 残りのUIをコントロール・ペインに追加します。例3-5に示されているコード行を、mediaBar.getChildren().add(playButton);行の後、setBottom(mediaBar)行の前に追加します。

    例3-5 残りのUIコントロールの追加

    // Add spacer
    Label spacer = new Label("   ");
    mediaBar.getChildren().add(spacer);
     
    // Add Time label
    Label timeLabel = new Label("Time: ");
    mediaBar.getChildren().add(timeLabel);
     
    // Add time slider
    timeSlider = new Slider();
    HBox.setHgrow(timeSlider,Priority.ALWAYS);
    timeSlider.setMinWidth(50);
    timeSlider.setMaxWidth(Double.MAX_VALUE);
    mediaBar.getChildren().add(timeSlider);
    
    // Add Play label
    playTime = new Label();
    playTime.setPrefWidth(130);
    playTime.setMinWidth(50);
    mediaBar.getChildren().add(playTime);
     
    // Add the volume label
    Label volumeLabel = new Label("Vol: ");
    mediaBar.getChildren().add(volumeLabel);
     
    // Add Volume slider
    volumeSlider = new Slider();        
    volumeSlider.setPrefWidth(70);
    volumeSlider.setMaxWidth(Region.USE_PREF_SIZE);
    volumeSlider.setMinWidth(30);
     
    mediaBar.getChildren().add(volumeSlider);
    
  8. 例3-6に示されているインポート文をファイルの先頭に追加します。

    例3-6 さらなるインポート文の追加

    import javafx.scene.layout.Priority;
    import javafx.scene.layout.Region;
    

機能ロジック・コードの追加

すべてのコントロールを作成してコントロール・パネルに追加した後、メディアの再生を管理し、アプリケーションを対話的にするための機能ロジックを追加します。

  1. 「Play」ボタンのイベント・ハンドラとリスナーを追加します。例3-7に示されているコード行を、final Button playButton = new Button(">")行の後、mediaBar.getChildren().add(playButton)行の前に追加します。

    例3-7 「Play」ボタンのイベント・ハンドラとリスナーの追加

    playButton.setOnAction(new EventHandler<ActionEvent>() {
        public void handle(ActionEvent e) {
            Status status = mp.getStatus();
     
            if (status == Status.UNKNOWN  || status == Status.HALTED)
            {
               // don't do anything in these states
               return;
            }
     
              if ( status == Status.PAUSED
                 || status == Status.READY
                 || status == Status.STOPPED)
              {
                 // rewind the movie if we're sitting at the end
                 if (atEndOfMedia) {
                    mp.seek(mp.getStartTime());
                    atEndOfMedia = false;
                 }
                 mp.play();
                 } else {
                   mp.pause();
                 }
             }
       });
    
  2. エラーを回避するために、例3-7から追加したコードによって使用されるインポート文を事前に追加しておくことができます。ただし、今回は、マークされたすべてのエラーを排除するために、[Ctrl]キーと[Shift]キーを押しながら[I]キーを押すか、任意の場所で右クリックして「インポートを修正」を選択します。「すべてのインポートを修正」ダイアログで、ドロップダウン・メニューからjavafx.scene.media.MediaPlayer.Statusjavafx.event.ActionEventおよびjavafx.event.EventHandlerを選択します。「OK」をクリックします。

  3. 次のコード行を、例3-7から追加したコード行の直後で、mediaBar.getChildren().add(playButton)という行の前に追加します。このコードにより、リスナーが処理されます。

    例3-8 リスナー・コードの追加

    mp.currentTimeProperty().addListener(new InvalidationListener() 
            {
                public void invalidated(Observable ov) {
                    updateValues();
                }
            });
     
            mp.setOnPlaying(new Runnable() {
                public void run() {
                    if (stopRequested) {
                        mp.pause();
                        stopRequested = false;
                    } else {
                        playButton.setText("||");
                    }
                }
            });
     
            mp.setOnPaused(new Runnable() {
                public void run() {
                    System.out.println("onPaused");
                    playButton.setText(">");
                }
            });
     
            mp.setOnReady(new Runnable() {
                public void run() {
                    duration = mp.getMedia().getDuration();
                    updateValues();
                }
            });
     
            mp.setCycleCount(repeat ? MediaPlayer.INDEFINITE : 1);
            mp.setOnEndOfMedia(new Runnable() {
                public void run() {
                    if (!repeat) {
                        playButton.setText(">");
                        stopRequested = true;
                        atEndOfMedia = true;
                    }
                }
           });
    

    表示されるエラーは、次の手順でさらにコードを追加することによって修正されます。

  4. 次のコード・スニペットをtimeSlider.setMaxWidth(Double.MAX_VALUE)という行の後、mediaBar.getChildren().add(timeSlider)という行の前に追加して、タイム・スライダのリスナーを追加します。

    例3-9 タイム・スライダのリスナーの追加

    timeSlider.valueProperty().addListener(new InvalidationListener() {
        public void invalidated(Observable ov) {
           if (timeSlider.isValueChanging()) {
           // multiply duration by percentage calculated by slider position
              mp.seek(duration.multiply(timeSlider.getValue() / 100.0));
           }
        }
    });
    
  5. 次のコード・スニペットをvolumeSlider.setMinWidth(30)という行の後、mediabar.getChildren().add(volumeSlider)という行の前に追加して、音量スライダ・コントロールのリスナーを追加します。

    例3-10 音量コントロールのリスナーの追加

    volumeSlider.valueProperty().addListener(new InvalidationListener() {
        public void invalidated(Observable ov) {
           if (volumeSlider.isValueChanging()) {
               mp.setVolume(volumeSlider.getValue() / 100.0);
           }
        }
    });
    
  6. 再生コントロールによって使用されるメソッドupdateValuesを作成します。それをpublic MediaControl()メソッドの後に追加します。

    例3-11 updateValuesメソッドの追加

    protected void updateValues() {
      if (playTime != null && timeSlider != null && volumeSlider != null) {
         Platform.runLater(new Runnable() {
            public void run() {
              Duration currentTime = mp.getCurrentTime();
              playTime.setText(formatTime(currentTime, duration));
              timeSlider.setDisable(duration.isUnknown());
              if (!timeSlider.isDisabled() 
                && duration.greaterThan(Duration.ZERO) 
                && !timeSlider.isValueChanging()) {
                  timeSlider.setValue(currentTime.divide(duration).toMillis()
                      * 100.0);
              }
              if (!volumeSlider.isValueChanging()) {
                volumeSlider.setValue((int)Math.round(mp.getVolume() 
                      * 100));
              }
            }
         });
      }
    }
    
  7. updateValues()メソッドの後に、private method formatTime()を追加します。formatTime()メソッドは、メディアが再生されている経過時間を計算し、コントロール・ツールバーに表示されるようにそれをフォーマットします。

    例3-12 経過時間を計算するメソッドの追加

    private static String formatTime(Duration elapsed, Duration duration) {
       int intElapsed = (int)Math.floor(elapsed.toSeconds());
       int elapsedHours = intElapsed / (60 * 60);
       if (elapsedHours > 0) {
           intElapsed -= elapsedHours * 60 * 60;
       }
       int elapsedMinutes = intElapsed / 60;
       int elapsedSeconds = intElapsed - elapsedHours * 60 * 60 
                               - elapsedMinutes * 60;
     
       if (duration.greaterThan(Duration.ZERO)) {
          int intDuration = (int)Math.floor(duration.toSeconds());
          int durationHours = intDuration / (60 * 60);
          if (durationHours > 0) {
             intDuration -= durationHours * 60 * 60;
          }
          int durationMinutes = intDuration / 60;
          int durationSeconds = intDuration - durationHours * 60 * 60 - 
              durationMinutes * 60;
          if (durationHours > 0) {
             return String.format("%d:%02d:%02d/%d:%02d:%02d", 
                elapsedHours, elapsedMinutes, elapsedSeconds,
                durationHours, durationMinutes, durationSeconds);
          } else {
              return String.format("%02d:%02d/%02d:%02d",
                elapsedMinutes, elapsedSeconds,durationMinutes, 
                    durationSeconds);
          }
          } else {
              if (elapsedHours > 0) {
                 return String.format("%d:%02d:%02d", elapsedHours, 
                        elapsedMinutes, elapsedSeconds);
                } else {
                    return String.format("%02d:%02d",elapsedMinutes, 
                        elapsedSeconds);
                }
            }
        }
    
  8. 最後に、インポートを修正します。空白の任意の場所で右クリックし、「すべてのインポートを修正」ダイアログでjavafx.application.Platformjavafx.beans.Observableを選択します。「OK」をクリックします。

EmbeddedMediaPlayer.javaの変更

コントロールを追加するには、前の章で作成したEmbeddedMediaPlayer.javaファイルを変更して、MediaControlオブジェクトを追加するためのコードを追加します。

  1. 例3-13のコード行をコピーして、mediaPlayer.setAutoPlay(true)行の直後に貼り付けます。

    例3-13 MediaControlオブジェクトを作成するためのソース・コードの追加

    MediaControl mediaControl = new MediaControl(mediaPlayer);
    scene.setRoot(mediaControl);
    
  2. 以前にmediaViewオブジェクトとmediaPlayerオブジェクトを作成した、例3-14に示されている3行を削除します。

    例3-14 コード行の削除

    // create mediaView and add media player to the viewer
     MediaView mediaView = new MediaView(mediaPlayer);
         ((Group)scene.getRoot()).getChildren().add(mediaView);
    
  3. MediaViewのインポート文import javafx.scene.media.MediaView;を削除します。

  4. 追加したメディア・コントロールが表示されるように、シーンの高さのサイズを調整します。

    例3-15 シーンの高さの変更

    Scene scene = new Scene(root, 540, 241);
    

EmbeddedMediaのコンパイルと実行

次に、前の項で作成したアプリケーションをビルドし、実行します。

  1. EmbeddedMediaPlayerプロジェクト・ノードを右クリックして、「消去してビルド」を選択します。

  2. ビルド・エラーがない場合は、再びノードを右クリックして「実行」を選択します。図3-2に類似した、コントロールのあるメディア・プレーヤが表示され、再生が開始されます。

    図3-2 再生コントロールのあるメディア・プレーヤ

    図3-2の説明が続きます
    「図3-2 再生コントロールのあるメディア・プレーヤ」の説明

  3. 「play/pause」コントロール・ボタンを使用して、ビデオを停止し、再開します。経過時間バーを使用して、ビデオを先送りまたは逆送りします。「volume」コントロール・ボタンを使用して、音量を調整します。

    完全なアプリケーション・コードは、EmbeddedMediaPlayer.zipファイルにあります。

ウィンドウを閉じる

目次

JavaFX: JavaFXアプリケーションへのメディア・アセットの組込み

展開 | 縮小