简体   繁体   中英

JavaFx Slider thumb listener

I am trying to create a media player using java fx slider. I would like to incorporate the play button with the slider thumb. So when user click on the slider's thumb it will activate the media player to play and the slider will move accordingly when its played. From the documentation the listeners is for the slider and not the slider's thumb. Any suggestion or ideas how the listener can be implemented?

I don't think the Slider control was implemented for that purpose, it might be possible but would require a lot of hacking, Why do you have to limit yourself like that ?

I suggest implementing a simple custom control and styling it like to look a slider, or even better you can add an icon inside the thumb, to indicate the state (Playing / Paused), you can basically do whatever you want with it.

I have written the following example which uses a StackPane as a parent, then uses StackPanes for children (the full-width bar and the progress bar, also the thumb) :

I named the class MediaSlider and it extends StackPane

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

public class MediaSlider extends StackPane {
    private String main = "#6200ee";
    private String sec = "#c6aee6";

    private DoubleProperty value;

    private StackPane thumb;

    private ImageView icon;
    private Image playImage, pauseImage;

    public MediaSlider() {
        setAlignment(Pos.CENTER_LEFT);
        setMaxHeight(50);

        value = new SimpleDoubleProperty(0);

        StackPane bar = createRect(sec);
        bar.maxWidthProperty().bind(widthProperty());

        StackPane fill = createRect(main);
        fill.maxWidthProperty()
                .bind(widthProperty().subtract(heightProperty()).multiply(value).add(heightProperty().divide(2)));

        thumb = new StackPane();
        thumb.setMaxWidth(Region.USE_PREF_SIZE);
        thumb.setMinWidth(Region.USE_PREF_SIZE);
        thumb.prefWidthProperty().bind(heightProperty());
        thumb.setCursor(Cursor.HAND);

        Circle circle = new Circle();
        circle.radiusProperty().bind(heightProperty().divide(2));
        circle.setFill(Color.web(main));

        playImage = new Image(getClass().getResourceAsStream("/play.png"));
        pauseImage = new Image(getClass().getResourceAsStream("/pause.png"));

        icon = new ImageView(playImage);
        icon.fitWidthProperty().bind(thumb.widthProperty().divide(2));
        icon.fitHeightProperty().bind(thumb.heightProperty().divide(2));
        
        thumb.getChildren().addAll(circle, icon);
        thumb.setEffect(new DropShadow(10, Color.gray(.0, .4)));
        thumb.translateXProperty().bind(widthProperty().subtract(thumb.widthProperty()).multiply(value));

        getChildren().addAll(bar, fill, thumb);

    }

    public void setOnThumbClicked(EventHandler<MouseEvent> handler) {
        thumb.setOnMouseClicked(handler);
    }

    public void pause() {
        icon.setImage(playImage);
    }

    public void play() {
        icon.setImage(pauseImage);
    }

    public void setValue(double value) {
        this.value.set(value);
    }

    public double getValue() {
        return value.get();
    }

    public DoubleProperty valueProperty() {
        return value;
    }

    private StackPane createRect(String color) {
        StackPane res = new StackPane();
        res.maxHeightProperty().bind(heightProperty().divide(5));
        res.setStyle("-fx-background-color: " + color + ";-fx-background-radius: 5;");
        return res;
    }
}

Then used it in the app in the following way

import java.io.IOException;
import java.net.URISyntaxException;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status;
import javafx.stage.Stage;
import javafx.util.Duration;

public class App extends Application {

    @Override
    public void start(Stage stage) throws IOException, URISyntaxException {
        StackPane root = new StackPane();
        root.setPadding(new Insets(20));
        root.setStyle("-fx-background-color: #e5e5e5");

        //load media
        MediaPlayer player = new MediaPlayer(new Media(getClass().getResource("/song.mp3").toURI().toString()));
        
        //instantiate your custom slider class
        MediaSlider s = new MediaSlider();

        //bind slider position to media position
        s.valueProperty().bind(Bindings.createDoubleBinding(() -> {
            double val = player.getCurrentTime().toSeconds() / player.getTotalDuration().toSeconds();
            return Double.isNaN(val) ? .0 : val;
        }, player.currentTimeProperty()));

        //handle click events
        s.setOnThumbClicked(event -> {
            if (player.getStatus().equals(Status.PLAYING)) {
                s.pause();
                player.pause();
                player.seek(player.getCurrentTime());
            } else {
                s.play();
                player.play();
            }
        });

        //replay on end of media
        player.setOnEndOfMedia(() -> player.seek(Duration.ZERO));

        root.getChildren().add(s);

        Scene scene = new Scene(root, 600, 300);
        stage.setScene(scene);
        stage.show();
    }

}

Here is how it looks :

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM