How to Change the Color of Progressbar in C# .Net 3.5

How to change the color of progressbar in C# .NET 3.5?

Since the previous answers don't appear to work in with Visual Styles. You'll probably need to create your own class or extend the progress bar:

public class NewProgressBar : ProgressBar
{
public NewProgressBar()
{
this.SetStyle(ControlStyles.UserPaint, true);
}

protected override void OnPaint(PaintEventArgs e)
{
Rectangle rec = e.ClipRectangle;

rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4;
if(ProgressBarRenderer.IsSupported)
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
rec.Height = rec.Height - 4;
e.Graphics.FillRectangle(Brushes.Red, 2, 2, rec.Width, rec.Height);
}
}

EDIT: Updated code to make the progress bar use the visual style for the background

Change (custom) ProgressBar color

It has nothing to do with the Property exactly, but the PInvoke is imperfect either in the source or your conversion. I suspect you started with this old C# answer.

Imports System.Runtime.InteropServices
Class NativeMethods
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=False)>
Private Shared Function SendMessage(hWnd As IntPtr,
Msg As UInt32,
w As IntPtr,
l As IntPtr) As IntPtr
End Function

Private Const PBM_SETSTATE = &H400 + 16
Friend Enum PBMStates
Normal = 1
[Error] = 2
Paused = 3
End Enum

Friend Shared Sub SetProgressState(ctl As ProgressBar, state As PBMStates)
SendMessage(ctl.Handle, PBM_SETSTATE, New IntPtr(state), IntPtr.Zero)
End Sub
End Class

According to the MSDN docs, PBM_SETSTATE returns the previous state. I've ignored that and made it a Sub. Since it only is supposed to be used with a ProgressBar I it to accept only a ProgressBar control rather than a control handle (which could be from any control). Finally, the code is Shared and in a NativeMethods class so CA will not complain. Usage:

NativeMethods.SetProgressState(ProgressBar1, NativeMethods.PBMStates.Error)

Result:

Sample Image

Visual Studio 2010: Progressbar does not change color?

Locate the following line of code within your solution (tipically in Program.cs):

Application.EnableVisualStyles();

Comment out this line. Now the color of the progress bar will change as expected, but the style of your controls will also change a little. I'm curremtly trying to find a better solution for this myself.

c#.Net Progress Bar Issue

As for first part of your question - try using following constructor for your brush:

new LinearGradientBrush(new Point(0, 0), new Point(0, Height - inset * 2), BackColor, ForeColor);

Your current brush has top control point at Y=inset - that's why area from Y=0 to Y=inset is all painted in solid color.

Changing the color of a progressbar in Visual Basic

Import SendMessage:

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
End Function

And use this function:

SendMessage(ProgressBar1.Handle, 1040, 2, 0)

Color codes:

1: green
2: red
3: yellow

Flickering custom ProgressBar

That's not flickering, that's a form of tearing. The Custom Control is not always drawn completely; it can happen if you have a close loop that doesn't allow the Form to repaint itself and its child controls correctly.

Possibly, make the procedure that fills the ProgressBar asynchronous.

Some suggested modifications to make it smoother:

  • Use floating point values for your calculations (don't cast to int), and use a RectagleF to define the bounds of your drawing.

  • Remove the Bitmap and set ControlStyles.OptimizedDoubleBuffer:

    If true, the control is first drawn to a buffer rather than directly to the screen, which can reduce flicker. If you set this
    property to true, you should also set the AllPaintingInWmPaint to true.

  • Then of course set ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint:

    AllPaintingInWmPaint: If true, the control ignores the window message WM_ERASEBKGND to reduce flicker.
    This style should only be applied if the UserPaint bit is set to true.

    UserPaint: If true, the control paints itself rather than the
    operating system doing so. If false, the Paint event is not raised.
    This style only applies to classes derived from Control.

  • ControlStyles.Opaque removes the background and lets ProgressBarRenderer do its job, to fill the base graphics of the ProgressBar.

Calculate the current width of ProgressBar's colored parts based on the current Value set:

float width = (this.Width - 3) * ((float)this.Value / this.Maximum)

If width > 0, then paint the ProgressBar colors using the Forecolor and BackColor properties. Of course you could use a different set of properties to define these colors.

Add some anti-alias to the drawing, setting the Graphics.SmoothingMode, to make the color transition generated by the LinearGradientBrush smoother. This is more useful when you set LinearGradientMode.Horizontal.

Resulting in:

Custom drawn ProgressBar



public class ProgressBarCustom : ProgressBar
{
public ProgressBarCustom()
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.Opaque, true);
}

protected override void OnPaint(PaintEventArgs e)
{
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, ClientRectangle);

float width = (Width - 3) * ((float)Value / Maximum);
if (width > 0) {
var rect = new RectangleF(1, 1, width, Height - 3);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
using (var brush = new LinearGradientBrush(rect, BackColor, ForeColor, LinearGradientMode.Horizontal)){
e.Graphics.FillRectangle(brush, rect);
}
}
}
}

As a small improvement, you could draw a line 9 pixels in height, with a semi-transparent color, to the top side of the ProgressBar, to simulate the original reflection.

Change the code to add Graphics.DrawLine():

// [...]
using (var brush = new LinearGradientBrush(rect, BackColor, ForeColor, LinearGradientMode.Horizontal))
using (var pen = new Pen(Color.FromArgb(40, 240,240,240), 9)) {
e.Graphics.FillRectangle(brush, rect);
e.Graphics.DrawLine(pen, 1.0f, 1.0f, width, 1.0f);
}

Custom drawn ProgressBar + reflaction

How do I change the color of my progress bar in Inno Setup?

You cannot.


The progress bar is styled by the current Windows theme. In the default Windows theme, the progress bar is green (or yellow or red, if the progress bar is in paused or error state, see TNewProgressBar.State).

You would have to completely reimplement the drawing of the progress bar or disable visual themes of whole installer.

See How to change the color of progressbar in C# .NET 3.5?

With the Inno Setup API it would very difficult if possible at all to reimplement the drawing. And you probably do not want to disable the visual themes.


If you really need the blue color, you may consider implementing the progress bar yourself using TBitmapImage.Bitmap.Canvas (using methods like .Rectangle).

A simple example:

var
ProgressImage: TBitmapImage;

procedure InitializeWizard();
begin
ProgressImage := TBitmapImage.Create(WizardForm);
ProgressImage.Parent := WizardForm;
ProgressImage.Left := ScaleX(10);
ProgressImage.Top := WizardForm.ClientHeight - ScaleY(34);
ProgressImage.Width := ScaleX(200);
ProgressImage.Height := ScaleY(20);
ProgressImage.BackColor := clWhite;
ProgressImage.Bitmap.Width := ProgressImage.Width;
ProgressImage.Bitmap.Height := ProgressImage.Height;
end;

procedure DrawProgress(Image: TBitmapImage; Progress: Integer);
var
Canvas: TCanvas;
Width: Integer;
begin
Log(Format('Drawing progress %d', [Progress]));

Canvas := Image.Bitmap.Canvas;

Canvas.Pen.Style := psClear;

Width := Image.Bitmap.Width * Progress / 100
Log(Format('Bar size: %d x %d', [Width, Image.Bitmap.Height]));

Canvas.Brush.Color := clHighlight;
Canvas.Rectangle(1, 1, Width, Image.Bitmap.Height);

Canvas.Brush.Color := clBtnFace;
Canvas.Rectangle(Width - 1, 1, Image.Bitmap.Width, Image.Bitmap.Height);

Canvas.Pen.Style := psSolid;
Canvas.Pen.Mode := pmCopy;
Canvas.Pen.Color := clBlack;
Canvas.Brush.Style := bsClear;
Canvas.Rectangle(1, 1, Image.Bitmap.Width, Image.Bitmap.Height);
end;

procedure CurPageChanged(CurPageID: Integer);
begin
Log(Format('CurPageChanged %d', [CurPageID]));
DrawProgress(ProgressImage, (CurPageID * 100 / wpFinished));
end;

Drawn progress bar



Related Topics



Leave a reply



Submit