0

I currently have a slider that I am styling with CSS. What I want is the range to change color when the thumb is slid. Similar to this picture:

enter image description here

How can I do this using only CSS? Below is what I have tried so far.

.range-slider .range-bar {
-fx-background-color: red;
}
James_D
  • 201,275
  • 16
  • 291
  • 322
Tony96
  • 31
  • 1
  • 5
  • not supported - you would need to implement a custom SliderSkin. BTW, wondering where you got those selectors from? Not in https://docs.oracle.com/javase/9/docs/api/javafx/scene/doc-files/cssref.html#slider .. – kleopatra Apr 04 '18 at 09:04
  • 1
    @kleopatra Actually possible (just about) with CSS and some magic with linear gradients... – James_D Apr 04 '18 at 12:10

1 Answers1

2

You can do this by using a linear-gradient for the track background, and binding the point where the gradient changes to the slider's value. The basic idea would be that when, e.g., the slider's value is at 50%, the background should be defined by

.slider .track {
    -fx-background-color: linear-gradient(to right, red 0%, red 50%, -fx-base 50%, -fx-base 100%);
}

but the 50% should change according to the slider's value.

So define the following in a CSS file (I introduced some extra looked-up colors to make it easier to modify the style):

.slider {
    /* default track color: */
    -slider-filled-track-color: red ;
    -slider-track-color: -slider-filled-track-color ;
}

/* Make thumb same color as filled part of track */
.slider .thumb {
    -fx-background-color: -slider-filled-track-color ;
}

.slider .track {
    -fx-background-color: -slider-track-color ;
}

and then you can do

    slider.styleProperty().bind(Bindings.createStringBinding(() -> {
        double percentage = (slider.getValue() - slider.getMin()) / (slider.getMax() - slider.getMin()) * 100.0 ;
        return String.format("-slider-track-color: linear-gradient(to right, -slider-filled-track-color 0%%, "
                + "-slider-filled-track-color %f%%, -fx-base %f%%, -fx-base 100%%);", 
                percentage, percentage);
    }, slider.valueProperty(), slider.minProperty(), slider.maxProperty()));

to bind the place where the color changes to the value of the slider.

Here's a SSCCE:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class SliderStyleTest extends Application {

    private static final String SLIDER_STYLE_FORMAT = 
            "-slider-track-color: linear-gradient(to right, -slider-filled-track-color 0%%, "
                    + "-slider-filled-track-color %1$f%%, -fx-base %1$f%%, -fx-base 100%%);";

    @Override
    public void start(Stage primaryStage) {
        Slider slider = new Slider();
        slider.styleProperty().bind(Bindings.createStringBinding(() -> {
            double percentage = (slider.getValue() - slider.getMin()) / (slider.getMax() - slider.getMin()) * 100.0 ;
            return String.format(SLIDER_STYLE_FORMAT, percentage);
        }, slider.valueProperty(), slider.minProperty(), slider.maxProperty()));

        StackPane root = new StackPane(slider);
        root.setPadding(new Insets(10));
        Scene scene = new Scene(root);
        scene.getStylesheets().add("style.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

where style.css is just the CSS file above. This gives:

enter image description here

James_D
  • 201,275
  • 16
  • 291
  • 322
  • You should format the string applying the US locale, otherwise the default one will be used, and on some users' machines you'll get a comma instead of a dot after formatting the double, which is not valid css and it will cause "CSS Error parsing". String.format(Locale.US, SLIDER_STYLE_FORMAT, percentage). Though, greate solution! – Oleg Markelov Oct 11 '20 at 07:14