How to Style the Progressbar Component in Javafx

How can I style the ProgressBar component in JavaFX

I have marked this answer as community wiki.

If you have ideas for JavaFX ProgressBar styling outside of the original initial styling queries, please edit this post to add your styling ideas (or to link to them).

set the color of the progress bar itself

Answered in:

  • JavaFX ProgressBar: how to change bar color?

The answer demonstrates

  1. Dynamic styling of the progress bar, so that the bar's color changes depending upon the amount of progress made.
  2. Static styling of the progress bar, which just sets the bar's color forever to a defined color.

JavaFX 7 (caspian) on a Windows PC:

colored progress bar

JavaFX 8 (modena) on a Mac:

progress bar mac

Sometimes people like barbershop pole style gradients, like the bootstrap striped style:

  • ProgressBar Animated Javafx

barbershop quartet

set the background color of the progress bar (not the same as setting the background color)

Define an appropriate css style for the progress bar's "track":

.progress-bar > .track {
-fx-text-box-border: forestgreen;
-fx-control-inner-background: palegreen;
}

progress-bar background color

add a custom text node on top of the progress bar (to show the different states)

Answered in:

  • Draw a String onto a ProgressBar, like JProgressBar?

string on a progress bar

how to change the height of a progress bar:

Answered in:

  • How to get narrow progres bar in JavaFX?

Sample CSS:

.progress-bar .bar { 
-fx-padding: 1px;
-fx-background-insets: 0;
}

José Pereda gives a nice comprehensive solution for narrow progress bars in his answer to:

  • How to get a small ProgressBar in JavaFX

small progress

I am looking for the css class names and the css commands

The place to look is in the default JavaFX style sheet.

  • modena.css for Java 8.
  • caspian.css for Java 7.

The ProgressBar style definitions for caspian (Java 7) are:

.progress-bar {
-fx-skin: "com.sun.javafx.scene.control.skin.ProgressBarSkin";
-fx-background-color:
-fx-box-border,
linear-gradient(to bottom, derive(-fx-color,30%) 5%, derive(-fx-color,-17%));
-fx-background-insets: 0, 1;
-fx-indeterminate-bar-length: 60;
-fx-indeterminate-bar-escape: true;
-fx-indeterminate-bar-flip: true;
-fx-indeterminate-bar-animation-time: 2;
}

.progress-bar .bar {
-fx-background-color:
-fx-box-border,
linear-gradient(to bottom, derive(-fx-accent,95%), derive(-fx-accent,10%)),
linear-gradient(to bottom, derive(-fx-accent,38%), -fx-accent);
-fx-background-insets: 0, 1, 2;
-fx-padding: 0.416667em; /* 5 */
}

.progress-bar:indeterminate .bar {
-fx-background-color: linear-gradient(to left, transparent, -fx-accent);
}

.progress-bar .track {
-fx-background-color:
-fx-box-border,
linear-gradient(to bottom, derive(-fx-color,-15%), derive(-fx-color,2.2%) 20%, derive(-fx-color,60%));
-fx-background-insets: 0, 1;
}

.progress-bar:disabled {
-fx-opacity: -fx-disabled-opacity;
}

The progress bar style definitions for modena (Java 8) are:

.progress-bar {
-fx-indeterminate-bar-length: 60;
-fx-indeterminate-bar-escape: true;
-fx-indeterminate-bar-flip: true;
-fx-indeterminate-bar-animation-time: 2;
}
.progress-bar > .bar {
-fx-background-color: linear-gradient(to bottom, derive(-fx-accent, -7%), derive(-fx-accent, 0%), derive(-fx-accent, -3%), derive(-fx-accent, -9%) );
-fx-background-insets: 3 3 4 3;
-fx-background-radius: 2;
-fx-padding: 0.75em;
}
.progress-bar:indeterminate > .bar {
-fx-background-color: linear-gradient(to left, transparent, -fx-accent);
}
.progress-bar > .track {
-fx-background-color:
-fx-shadow-highlight-color,
linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border),
linear-gradient(to bottom,
derive(-fx-control-inner-background, -7%),
derive(-fx-control-inner-background, 0%),
derive(-fx-control-inner-background, -3%),
derive(-fx-control-inner-background, -9%)
);
-fx-background-insets: 0, 0 0 1 0, 1 1 2 1;
-fx-background-radius: 4, 3, 2; /* 10, 9, 8 */
}

The JavaFX CSS reference guide contains general information on the use of CSS in JavaFX (which differs somewhat from the use of CSS in HTML).

JavaFX ProgressBar: how to change bar color?

Answer updated to add a simple non-animated example with multiple progress bars

The code in your question should display two different colored progress bars, the fact that it doesn't is a bug in the JavaFX css processing system. Log the bug against the runtime project here: http://javafx-jira.kenai.com.

As a workaround, instead of calling setStyle on the progress bars, define the accent colors used to color progress bars within a stylesheet and add a style class to the progress bars. Then, you can create multiple progress bars within the same application, all with different colors.

As Uluk points out, you can use JavaFX 2.2 caspian.css in conjunction with the JavaFX 2 css reference guide and the JavaFX 2 css tutorial to determine how to style things.

Here is some sample code which customizes a progress bar based upon the information in those references.

Sample css:

/** progress.css
place in same directory as
ColoredProgressBarStyleSheet.java or SimpleColoredProgressBar.java
ensure build system copies the css file to the build output path */

.root { -fx-background-color: cornsilk; -fx-padding: 15; }

.progress-bar { -fx-box-border: goldenrod; }

.green-bar { -fx-accent: green; }
.yellow-bar { -fx-accent: yellow; }
.orange-bar { -fx-accent: orange; }
.red-bar { -fx-accent: red; }

Simple sample program:

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

// shows multiple progress bars drawn in different colors.
public class SimpleColoredProgressBar extends Application {
public static void main(String[] args) { launch(args); }

@Override public void start(Stage stage) {
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(
new ColoredProgressBar("red-bar", 0.2),
new ColoredProgressBar("orange-bar", 0.4),
new ColoredProgressBar("yellow-bar", 0.6),
new ColoredProgressBar("green-bar", 0.8)
);
layout.getStylesheets().add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
}

class ColoredProgressBar extends ProgressBar {
ColoredProgressBar(String styleClass, double progress) {
super(progress);
getStyleClass().add(styleClass);
}
}
}

Simple sample program output:

coloredbars

More complicated sample program with a single animated progress bar which changes color dynamically depending on the amount of progress made:

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

// shows a progress bar whose bar changes color depending on the amount of progress.
public class ColoredProgressBarStyleSheet extends Application {
public static void main(String[] args) { launch(args); }

private static final String RED_BAR = "red-bar";
private static final String YELLOW_BAR = "yellow-bar";
private static final String ORANGE_BAR = "orange-bar";
private static final String GREEN_BAR = "green-bar";
private static final String[] barColorStyleClasses = { RED_BAR, ORANGE_BAR, YELLOW_BAR, GREEN_BAR };

@Override public void start(Stage stage) {
final ProgressBar bar = new ProgressBar();

final Timeline timeline = new Timeline(
new KeyFrame(Duration.millis(0), new KeyValue(bar.progressProperty(), 0)),
new KeyFrame(Duration.millis(3000), new KeyValue(bar.progressProperty(), 1))
);

Button reset = new Button("Reset");
reset.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
timeline.playFromStart();
}
});

bar.progressProperty().addListener(new ChangeListener<Number>() {
@Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
double progress = newValue == null ? 0 : newValue.doubleValue();
if (progress < 0.2) {
setBarStyleClass(bar, RED_BAR);
} else if (progress < 0.4) {
setBarStyleClass(bar, ORANGE_BAR);
} else if (progress < 0.6) {
setBarStyleClass(bar, YELLOW_BAR);
} else {
setBarStyleClass(bar, GREEN_BAR);
}
}

private void setBarStyleClass(ProgressBar bar, String barStyleClass) {
bar.getStyleClass().removeAll(barColorStyleClasses);
bar.getStyleClass().add(barStyleClass);
}
});

final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(bar, reset);
layout.getStylesheets().add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();

timeline.play();
}
}

More complicated sample program output:

sample program output

Change style of progressbar javaFX

Just use an external CSS file and set a background image on the bar. The bar itself is represented by a Region with style class bar (see docs), so you just need something like

.progress-bar > .bar {
-fx-background-image: url("http://upload.wikimedia.org/wikipedia/commons/c/ce/Train_icon_small.png");
-fx-background-position: right ;
-fx-background-color: transparent ;
-fx-background-repeat: repeat-x ;
}

Complete example:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class TrainProgressBar extends Application {

@Override
public void start(Stage primaryStage) {
ProgressBar progressBar = new ProgressBar();
progressBar.setProgress(0);
Button startButton = new Button("Start");
startButton.setOnAction(e -> {
startButton.setDisable(true);
Task<Void> task = new Task<Void>() {
@Override
public Void call() throws Exception {
for (int i = 0; i < 100; i++) {
Thread.sleep(20);
updateProgress(i, 100);
}
updateProgress(100, 100);
return null ;
}
};
progressBar.progressProperty().bind(task.progressProperty());
task.setOnSucceeded(evt -> startButton.setDisable(false));
new Thread(task){{setDaemon(true);}}.start();
});

VBox root = new VBox(15, progressBar, startButton);
Scene scene = new Scene(root, 250, 100);
scene.getStylesheets().add("train-progress-bar.css");
primaryStage.setScene(scene);
primaryStage.show();
}

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

with train-progress-bar.css:

.root {
-fx-padding: 10 ;
-fx-alignment: center ;
}

.progress-bar > .bar {
-fx-background-image: url(http://upload.wikimedia.org/wikipedia/commons/c/ce/Train_icon_small.png);
-fx-background-position: right ;
-fx-background-color: transparent ;
-fx-background-repeat: repeat-x ;
}

Change JavaFX progress bar style

Simply overwrite the color constant -fx-accent the gradient colors are derived from:

.progress-bar > .bar {
-fx-accent: green;
-fx-background-color: linear-gradient(
from 0px .75em to .75em 0px,
repeat,
-fx-accent 0%,
-fx-accent 49%,
derive(-fx-accent, 30%) 50%,
derive(-fx-accent, 30%) 99%
);
}

JavaFX How to change ProgressBar color dynamically?

See also the StackOverflow JavaFX ProgressBar Community Wiki.


There is a workaround you can use until a bug to fix the sample code in your question is filed and fixed.

The code in this answer does a node lookup on the ProgressBar contents, then dynamically modifies the bar colour of the progress bar to any value you like.

import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class ProgressBarDynamicColor extends Application {
public static void main(String[] args) { launch(args); }
@Override public void start(Stage stage) {
PickedColorBar aquaBar = new PickedColorBar(0.4, Color.AQUA);
PickedColorBar fireBar = new PickedColorBar(0.6, Color.FIREBRICK);

HBox layout = new HBox(20);
layout.getChildren().setAll(aquaBar, fireBar);
layout.setStyle("-fx-background-color: -fx-box-border, cornsilk; -fx-padding: 15;");

stage.setScene(new Scene(layout));
stage.show();

aquaBar.wasShown();
fireBar.wasShown();
}

class PickedColorBar extends VBox {
private final ProgressBar bar;
private final ColorPicker picker;

private boolean wasShownCalled = false;

final ChangeListener<Color> COLOR_LISTENER = new ChangeListener<Color>() {
@Override public void changed(ObservableValue<? extends Color> value, Color oldColor, Color newColor) {
setBarColor(bar, newColor);
}
};

public PickedColorBar(double progress, Color initColor) {
bar = new ProgressBar(progress);
picker = new ColorPicker(initColor);

setSpacing(10);
setAlignment(Pos.CENTER);
getChildren().setAll(bar, picker);
}

// invoke only after the progress bar has been shown on a stage.
public void wasShown() {
if (!wasShownCalled) {
wasShownCalled = true;
setBarColor(bar, picker.getValue());
picker.valueProperty().addListener(COLOR_LISTENER);
}
}

private void setBarColor(ProgressBar bar, Color newColor) {
bar.lookup(".bar").setStyle("-fx-background-color: -fx-box-border, " + createGradientAttributeValue(newColor));
}

private String createGradientAttributeValue(Color newColor) {
String hsbAttribute = createHsbAttributeValue(newColor);
return "linear-gradient(to bottom, derive(" + hsbAttribute+ ",30%) 5%, derive(" + hsbAttribute + ",-17%))";
}

private String createHsbAttributeValue(Color newColor) {
return
"hsb(" +
(int) newColor.getHue() + "," +
(int) (newColor.getSaturation() * 100) + "%," +
(int) (newColor.getBrightness() * 100) + "%)";
}
}
}

The code uses inlined string processing of css attributes to manipulate Region backgrounds. Future JavaFX versions (e.g. JDK8+) will include a public Java API to manipulate background attributes, making obsolete the string processing of attributes from the Java program.

Sample program output:

colorchooserprogress

How do you make a gradient progress bar in JavaFX?

You just have to use CSS to select the bar of the progress-bar:

.progress-bar .bar {
-fx-background-color: linear-gradient(to right, #87CEEB, #2980b9);
}

Then just add your stylesheet to your scene:

scene.getStylesheets().add("Style.css");

screenshot

How to get narrow progres bar in JavaFX?

You'll have to mess around with the styling to get it any smaller. I really recommend taking a look a the caspian.css that's included with Javafx - that's the default style sheet. It helps a lot when trying to override the look and feel of the default skins. Here's an example I put together that shows how it can be done:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class ProgressBarTest extends Application {

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

@Override
public void start(final Stage stage) throws Exception {
//All the controls are added here
VBox box = new VBox();
box.getStylesheets().add("test.css");
ProgressBar pb = new ProgressBar(50);

box.getChildren().add(pb);

//Setting up your scene
Scene scene = new Scene(box);
stage.setScene(scene);

stage.show();
}
}

And here's the test.css I loaded up:

.progress-bar .bar {-fx-padding:1px; -fx-background-insets:0;}

And here is the output of the test app:

small progress

How to set specific css value for javaFX ProgressBar during Runtime?

I don't think this is possible using CSS alone. However a customized Skin could be used that replaces the bar Node with a ImageView and uses the bar as clip instead:

progress.BarBackgroundProgressBarSkin

public class BarBackgroundProgressBarSkin extends ProgressBarSkin {

public BarBackgroundProgressBarSkin(ProgressBar control) {
super(control);
}

private ImageView barBackground;

@Override
protected void initialize() {
super.initialize();

barBackground = new ImageView();

barBackground.setManaged(false);

barBackground.setPreserveRatio(false);
barBackground.getStyleClass().setAll("bar-background");
int barIndex;

List<Node> children = getChildren();
int size = children.size();

for (barIndex = 0; barIndex < size && !children.get(barIndex).getStyleClass().contains("bar"); barIndex++) {
}

Region bar = (Region) children.set(barIndex, barBackground);
barBackground.setClip(bar);

// fill the bar for clipping
bar.setBackground(new Background(new BackgroundFill(Color.WHITE, new CornerRadii(2), new Insets(3, 3, 4, 3))));
}

@Override
protected void layoutChildren(double x, double y, double w, double h) {
// set pos
barBackground.setLayoutX(x);
barBackground.setLayoutY(y);

// set size
barBackground.setFitHeight(h);
barBackground.setFitWidth(w);

super.layoutChildren(x, y, w, h);
}

}

style.css

.progress-bar {
-fx-skin: 'progress.BarBackgroundProgressBarSkin';
}

.progress-bar > .bar-background {
/* your image goes here */
-fx-image: url('http://i.stack.imgur.com/glUAd.png');
}

.progress-bar > .track {
-fx-background-color: transparent;
}

Demo

@Override
public void start(Stage primaryStage) {

ProgressBar progressBar = new ProgressBar();

StackPane root = new StackPane();
root.getChildren().add(progressBar);
progressBar.setPrefSize(300, 18);

Scene scene = new Scene(root, 200, 200);

scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());

Timeline tl = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(progressBar.progressProperty(), 0d)),
new KeyFrame(Duration.seconds(10), new KeyValue(progressBar.progressProperty(), 1d, Interpolator.EASE_OUT))
);

tl.setCycleCount(Animation.INDEFINITE);
tl.play();

primaryStage.setScene(scene);
primaryStage.show();
}


Related Topics



Leave a reply



Submit