JavaFX,MediaPlayer - 卷麻烦!为什么mediaPlayer的音量不会一点一点地改变?

时间:2013-03-18 14:53:55

标签: javafx-2

我将setVolume设置为0.0,然后在while循环中逐位更改音量。然而,音量从0.0跳到1.0?如何顺畅地改变音量? 我试过了

public class EngineSound extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        mp3File = new File(metronom);
        media = new Media(mp3File.toURI().toURL().toString());
        mediaPlayer = new MediaPlayer(media);
        mediaView = new MediaView(mediaPlayer);
        mediaPlayer.play();
        mediaPlayer.setVolume(0.0);
        slider = new Slider();

        slider.valueProperty().addListener(new ChangeListener<Number>() {
            public void changed(ObservableValue<? extends Number> ov, Number old_val, Number new_val) {
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        mediaPlayer.setVolume(slider.getValue());

                    }
                });
            }
        });

        double count = 1;
        while (count != 101) {
            for (int i = 0; i < 100000000; i++) {

            }
            slider.setValue(count / 100);
            count++;
            System.out.println(mediaPlayer.getVolume());
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题。

  • JavaFX代码应该在JavaFX Application Thread上执行,而不是在Swing事件派发线程上执行。

不使用EventQueue.invokeLater在Swing线程上执行,而是使用Platform.runLater在JavaFX线程上执行。

  • 根本没有理由使用Swing事件调度线程。

你的程序只使用JavaFX控件,所以不要在Swing线程上运行任何东西。

  • 您通常不需要ChangeListener中的任何线程切换呼叫。

即使使用EventQueue.invokeLater是错误的,在这种情况下你甚至不需要Platform.runLater,因为只有JavaFX应用程序线程应该修改Slider值。您可以在JavaFX Node文档中看到规则:

  

应用程序必须将节点附加到场景,并在JavaFX应用程序线程上修改已附加到场景的节点。

  • 不要忙于等待JavaFX应用程序线程。

您计入一亿的循环将阻止应用程序线程导致冻结的UI,因为控件永远不会返回到框架以更新UI。

  • 请勿更改循环中的滑块值。

在UI控件上设置值后,必须将控制权返回给JavaFX框架,以允许值更改反映在控件和用户中。

尝试以下代码,通过TimelineBinding解决所有上述问题。

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.event.*;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.media.*;
import javafx.stage.Stage;
import javafx.util.Duration;

public class EngineSound extends Application {
  private static final String MEDIA_URL = 
    "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv";

  private static final Duration FADE_DURATION = Duration.seconds(2.0);

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

  @Override public void start(Stage stage) throws Exception {
    final MediaPlayer mediaPlayer = new MediaPlayer(
      new Media(
        MEDIA_URL
      )
    );
    final MediaView mediaView = new MediaView(mediaPlayer);

    HBox layout = new HBox(5);
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
    layout.getChildren().addAll(
      createVolumeControls(mediaPlayer), 
      mediaView
    );
    stage.setScene(new Scene(layout, 650, 230));
    stage.show();           

    mediaPlayer.play();
  }

  public Region createVolumeControls(final MediaPlayer mediaPlayer) {
    final Slider volumeSlider = new Slider(0, 1, 0);
    volumeSlider.setOrientation(Orientation.VERTICAL);

    mediaPlayer.volumeProperty().bindBidirectional(volumeSlider.valueProperty());

    final Timeline fadeInTimeline = new Timeline(
      new KeyFrame(
        FADE_DURATION,
        new KeyValue(mediaPlayer.volumeProperty(), 1.0)
      )
    );

    final Timeline fadeOutTimeline = new Timeline(
      new KeyFrame(
        FADE_DURATION,
        new KeyValue(mediaPlayer.volumeProperty(), 0.0)
      )
    );

    Button fadeIn = new Button("Fade In");
    fadeIn.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent t) {
        fadeInTimeline.play();
      }
    });
    fadeIn.setMaxWidth(Double.MAX_VALUE);

    Button fadeOut = new Button("Fade Out");
    fadeOut.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent t) {
        fadeOutTimeline.play();
      }
    });
    fadeOut.setMaxWidth(Double.MAX_VALUE);

    VBox controls = new VBox(5);
    controls.getChildren().setAll(
      volumeSlider,
      fadeIn,
      fadeOut
    );
    controls.setAlignment(Pos.CENTER);
    VBox.setVgrow(volumeSlider, Priority.ALWAYS);

    controls.disableProperty().bind(
      Bindings.or(
        Bindings.equal(Timeline.Status.RUNNING, fadeInTimeline.statusProperty()),
        Bindings.equal(Timeline.Status.RUNNING, fadeOutTimeline.statusProperty())
      )
    );

    return controls;
  }
}

代码控制视频,但只使用音频只需将媒体网址设置为仅音频格式,如mp3或aac。

volumecontrolsample