16
$\begingroup$

I want to change the color of the progress bar in a ProgressIndicator. I want the progress bar to be red instead of green. For this purpose I wrote the following code, but still it doesn't work.

Style[ProgressIndicator[90, {0, 100}], Red]

Mathematica graphics

How can I do change the color?

$\endgroup$
1
  • $\begingroup$ @Nasser but in my App,some times same ProgressIndicator have Red color,and some times have Greencolor.and also for every time,ProgressIndicatorrange will change.then how can I solve this. $\endgroup$
    – subbu
    Mar 2, 2013 at 8:29

4 Answers 4

23
$\begingroup$

Don't forget, with M we have all of Java at our fingertips with just a few keystrokes. So why don't you use Java Swing, which is a professional UI framework that runs on hundreds of millions of devices.

enter image description here

I have ShowProgressBar and DestroyProgressBar in my init.m, because I use them frequently.

Needs["JLink`"]

ReinstallJava[]

ShowProgressBar[title_String: "Computation Progress",caption_String: "Percent complete:",percent_Integer: 0]:=JavaBlock[Module[{frame,panel,label,bar},InstallJava[];
bar=JavaNew["javax.swing.JProgressBar"];
frame=JavaNew["javax.swing.JFrame",title];
frame@setSize[300,110];
frame@setResizable[False];
frame@setLocation[400,400];
panel=JavaNew["javax.swing.JPanel"];
panel@setLayout[Null];
frame@getContentPane[]@add[panel];
label=JavaNew["javax.swing.JLabel",caption];
label@setBounds[20,10,260,20];
panel@add[label];
bar@setBounds[20,40,260,30];
bar@setMinimum[0];
bar@setMaximum[100];
bar@setValue[percent];
bar@setStringPainted[True];
panel@add[bar];
JavaShow[frame];
KeepJavaObject[bar,label];
{bar,label}]];

DestroyProgressBar[bar_?JavaObjectQ]:=JavaBlock[LoadJavaClass["javax.swing.SwingUtilities"];
SwingUtilities`windowForComponent[bar]@dispose[];
ReleaseJavaObject[bar]];

LoadJavaClass["javax.swing.UIManager"];
UIManager`setLookAndFeel["com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"];
{mybar,mylabel}=ShowProgressBar[];
([email protected];If[#==0,label="Ping",If[#==100,label="Pong"]];mylabel@setText[label];mybar@setValue[#])&/@With[{t=Range[0,100]},Join[t,Reverse@t,t,Reverse@t,t]];
DestroyProgressBar@mybar;

You can modify the Swing widgets any way you like, you can change the color to whatever you like, the backgrounds, the texts, the fonts, the sizes, the margins, etc., but for me, just changing the look-and-feel to Nimbus is doing it (default is Ocean, not too ugly either). This solution also has the advantage that you get a new window, which you can drag anywhere you want on your screens, you are not limited to having to see the progress bar in the M f/e at a fixed cell location. You can set the "Always on top" property, transparency, etc., because it's a WINDOW, and not just a WIDGET in the M f/e. I generally prefer having something like this in a new window that I can move away, otherwise I'd have to hunt down the location of the progress bar in the f/e to see updated values, i. e. scroll around until I found my cell. With longer computations I'd want to continue on something else in the M f/e and STILL be able to see the progress immediately, without hunting down cell locations manually. But that's a matter of personal preference. Swing gives you incredible flexibility (and plasticity and hardware acceleration -- because it's based on Java2D, etc.), and not just for widgets, but also for window management. And with JLink you can harness all that directly from your M session.

EDIT:

If it's important that it's really red, you can use one of various ways to set that. You could a) use the NimbusRed that is predefined and goes along with the Nimbus look-and-feel, b) set Red as the RGB value 255,0,0, or c) use the static constant red (or RED) from awt.

a) NimbusRed

enter image description here

LoadJavaClass["javax.swing.UIManager"];
UIManager`setLookAndFeel["com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"];
With[{defaults=UIManager`getLookAndFeelDefaults[]},
defaults@put[MakeJavaObject@"nimbusOrange",defaults@get[MakeJavaObject@"nimbusRed"]]];
{mybar,mylabel}=ShowProgressBar[];
([email protected];If[#==0,label="Ping",If[#==100,label="Pong"]];mylabel@setText[label];mybar@setValue[#])&/@With[{t=Range[0,100]},Join[t,Reverse@t,t,Reverse@t,t]];
DestroyProgressBar@mybar;

A list of Nimbus defaults is at Nimbus Defaults

b) Red with RGB 255,0,0

enter image description here

Instead of

defaults@get[MakeJavaObject@"nimbusRed"]

use

JavaNew["java.awt.Color",255,0,0]

c) use red or RED as awt constant:

use

Color`red

but you also have to load the Color class first:

LoadJavaClass["java.awt.Color",StaticsVisible->True];

Note that the entire look-and-feel makes further modifications to the display, due to plasticity / 3D effects, shading, etc. Pure red in Nimbus looks like Fruit Punch to me. But you also don't have to use Nimbus. You can use Motif, Metal, Ocean, etc., and there's a ton of third-party look-and-feels.

$\endgroup$
4
  • $\begingroup$ This looks nice, but just for the sake of detail (and to answer the questions exactly), how do you make the progress bar red? (I'm not that familiar with Swing) $\endgroup$
    – Ajasja
    Mar 2, 2013 at 22:07
  • $\begingroup$ @Ajasja: see my edit $\endgroup$ Mar 3, 2013 at 10:56
  • 3
    $\begingroup$ That's hardly what I'd call just a few keystrokes but +1 anyway for a cool demo. $\endgroup$
    – Mr.Wizard
    Mar 3, 2013 at 16:31
  • $\begingroup$ @Mr.Wizard: With that sentence I meant HAVING Java at your fingertips, i. e. the Needs and possibly the ReinstallJava[] (which in many cases is unnecessary as well). Once you do that, you're ready for Java from your M session. $\endgroup$ Mar 3, 2013 at 22:51
18
$\begingroup$

I know of no method by which to control the color of that element. I'm afraid that it may not be possible. I believe the style of the ProgressIndicator is taken from the OS settings, or rather the ProgressIndicator is rendered by the OS.

If you look at the on-line documentation for versions 7, 8, 9 you see that the style changes:

7: enter image description here
8: enter image description here
9: enter image description here

Further, I can tell you as a version 7, Windows 7 user that the appearance is like the third one, not the first, further indicating that these are generated by the OS and not Mathematica itself.

You can use an internal rendering independent of the OS with setting "Generic" but even then I don't know how to control the color of the bar.:

ProgressIndicator[0.8, BaseStyle -> ControlsRendering -> "Generic"]

Mathematica graphics

You should be able to craft your own progress indicator in the style you like by using Dynamic and Graphics.


As a proof of concept:

{myProgressIndicator[Dynamic[x], ChartStyle -> Red], Slider[Dynamic[x]]} // Column

Mathematica graphics

Code is:

myProgressIndicator[Dynamic[x_] | x_, opts : OptionsPattern[BarChart]] :=
 Dynamic@BarChart[{x}, opts, ChartElementFunction -> "GlassRectangle", BarOrigin -> Left, 
   Frame -> True, FrameTicks -> None, ImageSize -> {200, 22}, 
   PlotRange -> {{0, 1}, {0, 1}}, AspectRatio -> (22/200), ImageMargins -> 1, 
   PlotRangePadding -> 0]
$\endgroup$
2
  • $\begingroup$ Well, not always Rotate[ProgressIndicator[0.8], 10 \[Degree]] $\endgroup$
    – Ajasja
    Mar 2, 2013 at 8:49
  • $\begingroup$ @Ajasja Good point, I should include "Generic" in my answer. $\endgroup$
    – Mr.Wizard
    Mar 2, 2013 at 8:54
18
$\begingroup$

If you're on version 9, you can use gauges:

HorizontalGauge[90, {0, 100},  ScaleRangeStyle -> Red, 
  GaugeMarkers -> "ScaleRange"]

a gauge

I don't fully understand how Mathematica scales and aligns things like gauges (and it's not the sort of thing that's easy to find in the documentation) but I would explore the options using a Manipulate:

Manipulate[
  HorizontalGauge[90, {0, 100}, 
  ScaleDivisions -> 10, 
  GaugeMarkers -> "ScaleRange", 
  AspectRatio -> aspectRatio, 
  ImageSize -> {width, height}, 
  ScalePadding -> None],
{width, 150, 500}, 
{height, 50, 500}, 
{aspectRatio, .1, 5}] 

enter image description here

$\endgroup$
1
  • $\begingroup$ thanks for your answer,but I want to increase width of Gauge.for that purpose,I wrote the following code,HorizontalGauge[90, {0, 100}, ScaleDivisions -> 0, GaugeMarkers -> "ScaleRange", ImageSize -> {350, 100}, ScalePadding -> None].still it does not work.if we specify ImageSize,it applies to FrameMarginto the Gauge.I don't want to FrameMargin around the Gauge.I want to increase Widthonly.I tried,but I did't get it.how can I do this? $\endgroup$
    – subbu
    Mar 3, 2013 at 19:31
12
$\begingroup$

For this solution, I've made rasterized versions of ProgressIndicator, replacing green tones by similarly light/dark red tones by means of a function toRed. All other colors used by default are gray levels, i.e. they match the {c_,c_,c_} pattern. This works fine only for the appearance shown third in Mr. Wizard's answer (also seen below). What's left then is to simply rescale the arguments to select the proper part of the list, in which the rasterized versions are stored (rasterizing each time seperately takes too much time). For different appearances the replacement rules in toRed would have to be changed. Here's the code:

toRed[{c_, c_, c_}] := {c, c, c}
toRed[col : {r_, g_, b_}] := 
 256 List @@ Blend[{Red, GrayLevel[Mean@col/256]}]

myPIList = (Rasterize[ProgressIndicator@#] /. 
      col : {r_?NumberQ, g_?NumberQ, b_?NumberQ} :> toRed@col) & /@ 
   Range[0, 1, 0.01];

myProgressIndicator[x_, r : {a_, b_} : {0, 1}] :=
 myPIList[[Round@Rescale[
     If[NumericQ@x, x, 0], r, {1, 101}]]]

And here's an example:

ProgressIndicator[87, {12, 140}]
myProgressIndicator[87, {12, 140}]

enter image description here

What seperates this method from the other ones is that the overall appearance is very close to the default one, only the color is changed. Of course some tweaking is still needed, e.g. to make this work with Dynamic.

$\endgroup$
3
  • $\begingroup$ Clever. +1, although I posted one of my own. If overall appearance remaining the default is an advantage, is a matter of personal preference. Oftentimes you want things sufficiently different. I, for one, would NOT want the progress bar to be so close to the input cell, I want it in a new window, where I can move it away, so I have it in my view when I'm working on other parts of the .nb. What if you don't like the default behavior? But definitely a clever use of image manipulation. I'd give you +5 for cleverness if I could. $\endgroup$ Mar 4, 2013 at 22:35
  • $\begingroup$ Stating that this was an advantage was maybe a bit of an exaggeration, but I thought it would be nice to have a solution that uses as much of the native design as possible. Of course, if you don't like the default anyway, it's obviously much better to construct your own progress indicator from scratch. $\endgroup$
    – einbandi
    Mar 4, 2013 at 22:40
  • $\begingroup$ ... and oftentimes it IS desirable to change just one property of something and leave everything else the same, so this is a very valid point as well. It simply depends. There are Java Swing look-and-feels that mimic the native o/s look, some people want a Java window to look exactly like a Windows window so all their windows have the same look-and-feel. Don't ask me why ... $\endgroup$ Mar 4, 2013 at 22:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.