Virtual Developer Workshop: Containerized Development with Docker

Gradient Progress Control (7961 bytes)  Download Source Code and Example

Development Environment: VC5, 95

This is a simple class to display a gradient fill progress control.  It works just like the normal progress control. The main enhancements are that you can customize the colors and toggle the percentage caption's visibility. 

The control can be incorporated into a project like any other CProgressCtrl derived control. Either create the control manually, subclass an existing CProgressCtrl, or use ClassWizard to DDX_control it.  The actual code for the progress control is located in GradientProgressCtrl.h and GradientProgressCtrl.cpp. I haven't fully tested it's robustness, although I don't suspect that it will fail miserably.  Most of the work happens in the DrawGradient(...) function, which also uses Keith Rule's MemDC class.  The sample project also uses Chris Maunder's ColourPicker.  Both of these classes are included in the sample project and can be downloaded elsewhere at this site.

It is derived from CProgressCtrl so all standard CProgressCtrl functions are available.  Additional functions are listed below.

I hope someone gives it a good home :).  Please let me know of any problems or improvements.  Thanks and good luck.

Member Set Functions

	void SetTextColor(COLORREF color)           // Set the percentage text color
	void SetBkColor(COLORREF color)             // Set background color
	void SetStartColor(COLORREF color)          // Set starting color
	void SetEndColor(COLORREF color)            // Set ending color
	void ShowPercent(BOOL bShowPercent = TRUE)  // Show the percent caption?

Member Get Functions

	COLORREF GetTextColor(void)		    
	COLORREF GetBkColor(void)	
	COLORREF GetStartColor(void)	
	COLORREF GetEndColor(void)


Last updated: 18 May 1998


  • GetPercent of CGradientProgressCtrl

    Posted by Legacy on 12/16/2003 08:00am

    Originally posted by: Micket

    CString CGradientProgressCtrl::GetPercent()
    CString percent;
    percent.Format("%.0f%%", 100.0f*(float)m_nCurrentPosition/(float)m_nUpper);

    return percent;

  • Error using OffsetPos

    Posted by Legacy on 03/23/2001 08:00am

    Originally posted by: Daniel Bayer

    Be aware of using OffsetPos instead of SetPos with this implementation of CGradiantProgressCtrl. Bugfix should be really simple, but i used the easy way an replaced OffsetPos by using SetPos. Thats it folks! Keep on improving Windows GUI and bring pleasure to the eyes of the world!

  • Vertical?

    Posted by Legacy on 07/27/1999 07:00am

    Originally posted by: john

    Anyway to make it work vertical also?

  • Update To the code that outputs the text

    Posted by Legacy on 07/15/1999 07:00am

    Originally posted by: Murali Soundararajan

    This code should replace the "Show percent indicator if needed" code in CGradientProgressCtrl::OnPaint(). It draws the text using colors that force the text to stand out regardless of the Gradient start & stop you choose.

    if (m_bShowPercent)
    CMemDC memDC(&dc);
    CDC dcMask;
    CDC dc2;

    // Create a place to work on our inverted text...

    // Certain types of bitmap operations require WORD aligned buffers
    CRect rectEven;
    0, // Upper left X
    0, // Upper left Y
    ((rectClient.Width()+7)*16)/16-1, // Lower right X
    ((rectClient.Height()+7)*16)/16-1); // Lower right Y

    // Create the text mask
    CBitmap bmShadow;
    VERIFY(bmShadow.CreateBitmap( rectEven.Width(),rectEven.Height(), 1, 1, NULL ) );

    CBitmap* pOldBitmap = dcMask.SelectObject(&bmShadow);

    CString percent;
    if (m_strOutput.IsEmpty())
    percent.Format("%3.0f %%", 100.0f*(float)nDrawPosition/(float)m_nUpper);
    percent = m_strOutput;

    RECT rectFill; // Rectangle for filling band
    0, // Upper left X
    0, // Upper left Y
    rectClient.Width()-1, // Lower right X
    rectClient.Height())-1; // Lower right Y

    // Blank the mask bitmap

    // Print The text in white text on the mask
    dcMask.DrawText(percent, &rectFill, DT_VCENTER | DT_CENTER | DT_SINGLELINE); // write out text

    // Create the invert color
    CBitmap bmInvertColor;
    bmInvertColor.CreateCompatibleBitmap(&dc,rectEven.Width(), rectEven.Height());
    CBitmap* pOldBitmapDC2 = dc2.SelectObject(&bmInvertColor);
    // copy get a copy of the screen
    // invert the colors in the copy
    // taken care of in NOTSRCCOPY VERIFY(dc2.BitBlt(0,0,rectClient.Width(),rectClient.Height(),NULL,0,0,DSTINVERT));
    // AND the "White" text mask to the Invert Colors => this produces our inverted color text

    // Now invert the text mask
    // Prepare screen - Apply inverted text mask to screen, ie erase data on screen we are going to replace

    // Now fill in the area we cleared using the "inverted text mask" by copying "inverted color text" to the screen


  • Percent string badly computed !

    Posted by Legacy on 05/10/1999 07:00am

    Originally posted by: Fabrice GIRARDOT

    The displayed percent string is badly evaluated.

    To fix it, use such formula :

    float percent = 100.0f;
    percent *= (float)(m_nCurrentPosition-m_nLower);
    percent /= (float)(m_nUpper-m_nLower);

    It may display value <0 or >100 if out of range !

    Anyway, this is a *GREAT* control !
    Thanks a lot.


  • Bug fix for Gradient Progress Control

    Posted by Legacy on 04/08/1999 07:00am

    Originally posted by: Rajesh Bobade

    Comment : Doesn't work when the start and end colors are same because the color 
    differences r,g,b workout to zero when the start and end colors are same.Consequently
    the value of nSteps(which is the max of r,g and b) also becomes zero.This ultimately
    used to miscalcutate the values for the width of each band(Step) and the step size for
    each color(rStep, gStep, and bStep).The Listing below shows the
    CGradientProgressCtrl::DrawGradient() function with the necesssary changes.

    void CGradientProgressCtrl::DrawGradient(CPaintDC *pDC, const RECT& rectClient, const int& nMaxWidth)
    RECT rectFill; // Rectangle for filling band
    float fStep; // How wide is each band?
    CBrush brush; // Brush to fill in the bar

    CMemDC memDC(pDC);

    //First find out the largest color distance between the start and
    //end colors.This distance will determine how many steps we use to
    //carve up the client region and the size of each gradient rect.

    int r, g, b; // First distance, then starting value
    float rStep, gStep, bStep; // Step size for each color
    BOOL bSameColor = FALSE;
    int nSteps;

    // Get the color differences
    r = (GetRValue(m_clrEnd) - GetRValue(m_clrStart));
    g = (GetGValue(m_clrEnd) - GetGValue(m_clrStart));
    b = (GetBValue(m_clrEnd) - GetBValue(m_clrStart));

    if((r == 0) && (g == 0) && (b == 0))
    bSameColor = TRUE;
    //Added the three lines below to fix the drawing
    //problem which used to occur when both the start
    //and end colors are same.
    r = GetRValue(m_clrStart);
    g = GetGValue(m_clrStart);
    b = GetBValue(m_clrStart);

    // Make the number of steps equal to the greatest distance
    //To fix the drawing problem which used to occur when
    //both the start and end colors are RGB(0,0,0).
    if(bSameColor && m_clrStart == 0)
    nSteps = 255;//Select max. possible value for nSteps
    nSteps = max(abs(r), max(abs(g), abs(b)));
    //Determine how large each band should be in order to cover the
    //client with nSteps bands (one for every color intensity level)
    fStep = (float)rectClient.right / (float)nSteps;

    //Calculate the step size for each color
    rStep = r/(float)nSteps;
    gStep = g/(float)nSteps;
    bStep = b/(float)nSteps;

    //Reset the colors to the starting position
    r = GetRValue(m_clrStart);
    g = GetGValue(m_clrStart);
    b = GetBValue(m_clrStart);

    // Start filling bands
    for (int iOnBand = 0; iOnBand < nSteps; iOnBand++)
    ::SetRect(&rectFill,(int)(iOnBand * fStep),0,
    (int)((iOnBand+1) * fStep),rectClient.bottom + 1);

    //CDC::FillSolidRect is faster, but it does not handle
    //8-bit color depth
    if(bSameColor) VERIFY(brush.CreateSolidBrush(m_clrStart));
    VERIFY(brush.CreateSolidBrush(RGB(r+rStep * iOnBand,
    g + gStep * iOnBand, b + bStep * iOnBand)));


    //If we are past the maximum for the current position we
    //need to get out of the loop.Before we leave,we repaint the
    //remainder of the client area with the background color.
    if(rectFill.right > nMaxWidth)
    rectClient.right, rectClient.bottom);

  • VC 6 - SetRange32

    Posted by Legacy on 02/23/1999 08:00am

    Originally posted by: Greg

    I thought I would point out in VC6 the CProgressCtrl has a SetRange and SetRange32 function. SetRange32 must have been added between VC5 and VC6, so you will need to override this function in the CGradientProgressCtrl class.

    Otherwise, this class works great! Thanks.

  • An Oddity

    Posted by Legacy on 02/18/1999 08:00am

    Originally posted by: Rick York

    I noticed an oddity with this control. At least, I think
    it's oddity - it is apparently by design. When the value
    of the progress hits its maximum the bar goes away.
    The reason this seems to be an oddity is that the standard
    progress bar does not exhibit this behavior.
    Luckily the fix for this is simple : on line 83 change
    the greater than or equal to just a greater than.
    It could be argued that if the value exceeds the maximum
    then just consider it to be AT the maximum but that is
    probably picking at nits.

    Nit-picking aside, this is a very nice control, thanks a lot !
    I am using it in an app I hope to be posting here soon :)

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date