JavaFX - 拖动鼠标按钮后设置Slider值

时间:2014-10-24 16:44:39

标签: user-interface javafx slider

我正在编写音乐播放器而且我不知道如何在用户释放鼠标按钮后编写滑块拖动处理程序以设置值。当我编写简单的MouseDragged方法时,拖动会带来非estetic"倒带"声音,因为每次滑块移动时,媒体播放器都会更改值。播放滑块时,媒体播放器监听器会自动更改值以与轨道持续时间同步。这是我到目前为止所得到的。

ChangeListener<Duration> timeListener =  new ChangeListener<Duration>() {
    @Override
    public void changed(
            ObservableValue<? extends Duration> observableValue,
            Duration duration,
            Duration current) {
        durSlider
                .setValue(current
                        .toSeconds());
    }
};

durSlider.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {

                    mediaPlayer.seek(Duration.seconds(durSlider.getValue()));

                    }

                });

1 个答案:

答案 0 :(得分:10)

valueChanging property of the slider表示滑块是否正在被更改。它是一个可观察的属性,因此您可以直接将侦听器附加到它,并在值停止更改时作出响应:

durSlider.valueChangingProperty().addListener(new ChangeListener<Boolean>() {
    @Override
    public void changed(ObservableValue<? extends Boolean> obs, Boolean wasChanging, Boolean isNowChanging) {
        if (! isNowChanging) {
            mediaPlayer.seek(Duration.seconds(durSlider.getValue()));
        }
    }
});

如果用户点击滑块上的“轨道”,或者使用键盘移动它,则不会改变播放器的位置。为此,您可以使用value属性注册侦听器。你需要在这里小心,因为价值也会通过你的时间听众改变。理论上,时间监听器应该设置滑块的值,然后这应该导致尝试将播放器的当前时间设置为它已经具有的确切值(这将导致无操作)。但是,舍入错误可能会导致很多小的调整,导致您观察到的“静态”。要解决此问题,只有在更改超过某个小的最小数量时才移动媒体播放器:

private static double MIN_CHANGE = 0.5 ; //seconds

// ...

durSlider.valueProperty().addListener(new ChangeListener<Number>() {
    @Override
    public void changed(ObservableValue<? extends Number> obs, Number oldValue, Number newValue) {
        if (! durSlider.isValueChanging()) {
            double currentTime = mediaPlayer.getCurrentTime().toSeconds();
            double sliderTime = newValue.doubleValue();
            if (Math.abs(currentTime - sliderTime) > 0.5) {
                mediaPlayer.seek(newValue.doubleValue());
            }
        }
    }
});

最后,如果用户试图拖动滑块,您不希望时间监听器移动滑块:

ChangeListener<Duration> timeListener =  new ChangeListener<Duration>() {
    @Override
    public void changed(
            ObservableValue<? extends Duration> observableValue,
            Duration duration,
            Duration current) {
        if (! durSlider.isValueChanging()) {
            durSlider.setValue(current.toSeconds());
        }
    }
};

这是一个完整的例子(为了简洁起见使用lambdas):

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
import javafx.util.Duration;

public class VideoPlayerTest extends Application {

    private static final String MEDIA_URL =
            "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv";

    private static final double MIN_CHANGE = 0.5 ;

    @Override
    public void start(Stage primaryStage) {
        MediaPlayer player = new MediaPlayer(new Media(MEDIA_URL));
        MediaView mediaView = new MediaView(player);

        Slider slider = new Slider();
        player.totalDurationProperty().addListener((obs, oldDuration, newDuration) -> slider.setMax(newDuration.toSeconds()));

        BorderPane root = new BorderPane(mediaView, null, null, slider, null);

        slider.valueChangingProperty().addListener((obs, wasChanging, isChanging) -> {
            if (! isChanging) {
                player.seek(Duration.seconds(slider.getValue()));
            }
        });

        slider.valueProperty().addListener((obs, oldValue, newValue) -> {
            if (! slider.isValueChanging()) {
                double currentTime = player.getCurrentTime().toSeconds();
                if (Math.abs(currentTime - newValue.doubleValue()) > MIN_CHANGE) {
                    player.seek(Duration.seconds(newValue.doubleValue()));
                }
            }
        });

        player.currentTimeProperty().addListener((obs, oldTime, newTime) -> {
            if (! slider.isValueChanging()) {
                slider.setValue(newTime.toSeconds());
            }
        });

        Scene scene = new Scene(root, 540, 280);
        primaryStage.setScene(scene);
        primaryStage.show();

        player.play();
    }

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