Draw a String onto a ProgressBar, like JProgressBar?

mattbdean picture mattbdean · Dec 27, 2012 · Viewed 11.2k times · Source

I recently started working with JavaFX, and started making FX versions of my custom Swing components. One of them was a count down timer, in which a JProgressBar was involved. I would draw the current time onto the bar using it's setString(String) method. Unfortunately, there does not seem to be such a method with JavaFX's ProgressBar. The closest thing I saw to what I was looking for was this:

timer (source)

I don't know if this would require a whole new custom component, or just a class like java.awt.Graphics.

Any help would be much appreciated. Thanks :)

Answer

jewelsea picture jewelsea · Dec 27, 2012

Here is a sample which (I think) does what your question is asking.

class ProgressIndicatorBar extends StackPane {
  final private ReadOnlyDoubleProperty workDone;
  final private double totalWork;

  final private ProgressBar bar  = new ProgressBar();
  final private Text        text = new Text();
  final private String      labelFormatSpecifier;

  final private static int DEFAULT_LABEL_PADDING = 5;

  ProgressIndicatorBar(final ReadOnlyDoubleProperty workDone, final double totalWork, final String labelFormatSpecifier) {
    this.workDone  = workDone;
    this.totalWork = totalWork;
    this.labelFormatSpecifier = labelFormatSpecifier;

    syncProgress();
    workDone.addListener(new ChangeListener<Number>() {
      @Override public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) {
        syncProgress();
      }
    });

    bar.setMaxWidth(Double.MAX_VALUE); // allows the progress bar to expand to fill available horizontal space.

    getChildren().setAll(bar, text);
  }

  // synchronizes the progress indicated with the work done.
  private void syncProgress() {
    if (workDone == null || totalWork == 0) {
      text.setText("");
      bar.setProgress(ProgressBar.INDETERMINATE_PROGRESS);
    } else {
      text.setText(String.format(labelFormatSpecifier, Math.ceil(workDone.get())));
      bar.setProgress(workDone.get() / totalWork);
    }

    bar.setMinHeight(text.getBoundsInLocal().getHeight() + DEFAULT_LABEL_PADDING * 2);
    bar.setMinWidth (text.getBoundsInLocal().getWidth()  + DEFAULT_LABEL_PADDING * 2);
  }
}

A complete executable test harness is also available.

Sample program output:

labeledprogressbar