Click here to Skip to main content
Click here to Skip to main content

A new progress bar for all occassions...

, 4 May 2003
Rate this:
Please Sign up or sign in to vote.
A CStatic derived Progress bar control that can indicate "busy states" effectively and double up as a good looking progress bar
<!-- Article image -->

Sample Image - kcbusyprogress.jpg

<!-- Add the rest of your HTML here -->

Description

This article describes a CStatic derived Progress bar that allows "busy" times with no defined end to be indicated with more than just an hourglass cursor.

Adding the code to your project

The CKCBusyProgress control can be subclassed within a dialog by following these steps:

  1. Insert the .h and .cpp files into your project
  2. Add a static control to your dialog resource
  3. Add a member variable for the static control (eg m_ctlBProgress)
  4. Change the variable declaration from :
    CStatic m_ctlBProgress;
    to:
    CKCBusyProgress m_ctlBProgress;
  5. et voila! You have the control embedded!

Public Functions

void SetNumSteps(int nNumSteps)

Sets the number of visible blocks in the control

int GetNumSteps()

Gets the number of visible blocks in the control

void SetCurPos(int nCurPos)

Sets the current position of the marker

int GetCurPos()

Gets the current position of the marker

void SetInterBlockPadding(int nPadding)

Sets the number of pixels between each block

int GetInterBlockPadding()

Gets the number of pixels between each block

void SetSpeed(int nSpeed)

Sets the speed (in milliseconds) of visual updates when the control is in BPC_MODE_BUSY mode

int GetSpeed()

Gets the speed (in milliseconds) of visual updates when the control isin BPC_MODE_BUSY mode

bool IsRunning()

Indicates whether the control is currently indicating a busy state (The control must be in BPC_MODE_BUSY mode)

void SetMode(int nMode = BPC_MODE_BUSY)

Sets the mode of the control
Valid parameters are:

BPC_MODE_BUSY 0x00000001 Puts the control into the BusyProgress mode (no range needed)
BPC_MODE_PROGRESS 0x00000002 Puts the control into the ProgressBar mode (can set a range - default is 0 .. 100)

int GetMode()

Gets the current mode of the control

void SetRange(int nLower, int nUpper)

Sets the lower and upper bounds of the control for when it is in BPC_MODE_PROGRESS mode

void GetRange(int& nLower, int& nUpper)

Gets the lower and upper bounds of the control

void Recalc()

Request the control to recalculate its internal visual aspects and ratios

void Reset()

Call this to reset the control to the state it was when it was first created

void Start()

Request the control to start its "busy" mode. This will only work if the control's mode is BPC_MODE_BUSY

void End()

Request the control to end its "busy" mode. This will only work if the control's mode is BPC_MODE_BUSY and the Start() function was called prior to this

void StepIt()

Call this function to manually "step" the control marker. This function works in both modes. When called in BPC_MODE_BUSY mode, the function will automatically cause the marker to change direction once it has reached either left or right control edge

COLORREF GetColBkg()

Gets the colour of the background

void SetColBkg(COLORREF col)

Sets the colour of the background
Remember to call UseSysColBkg(false) if you do not want changes in the system dialog colour to affect the control's background

COLORREF GetColBlockFace()

Gets the fill colour of the face of normal blocks

void SetColBlockFace(COLORREF col)

Sets the fill colour of the face of normal blocks

COLORREF GetColBlockEdge()

Gets the pen colour of the border of each normal block

void SetColBlockEdge(COLORREF col)

Sets the pen colour of the border of each normal block

COLORREF GetColBlockFaceHi()

Gets the fill colour of the face of highlighted blocks

void SetColBlockFaceHi(COLORREF col)

Sets the fill colour of the face of highlighted blocks

COLORREF GetColBlockEdgeHi()

Gets the pen colour of the border of each highlighted block

void SetColBlockEdgeHi(COLORREF col)

Sets the pen colour of the border of each highlighted block

void UseSysColBkg(bool bUse = true)

Indicates to the control whether its background is being drawn using the COLOR_3DFACE system colour or not. If bUse = true, the control will respond to WM_SYSCOLORCHANGE messages and update itself according to changes in system colours

void SetBusyType(int nType = BPC_BUSY_PINGPONG)

Indicates the type of motion employed when the control is running in BPC_MODE_BUSY mode. The 3 options are: BPC_BUSY_PINGPONG, BPC_BUSY_LTR, BPC_BUSY_RTL

int GetBusyType()

Gets the current type of motion that the control is using when in BPC_MODE_BUSY mode.

void SetBusyFill(int nFill = BPC_BUSYFILL_BLOCK)

Indicates the type of fill method used when the control is running in BPC_MODE_BUSY mode. The options are : BPC_BUSYFILL_BLOCK and BPC_BUSYFILL_SMOOTH

int GetBusyFill()

Gets the type of fill method used when the control is running in BPC_MODE_BUSY mode.

void SetGranularity(int nGranularity = 5)

Sets the level of granularity used when in BPC_MODE_BUSY mode and using the BPC_BUSYFILL_SMOOTH fill option. The higher the granularity, the smoother the fill will appear, but it will also take longer to get from one side of the control to the other

int GetGranularity()

Gets the level of granularity used when in BPC_MODE_BUSY mode and using BPC_BUSYFILL_SMOOTH fill option.

Overridable Functions

virtual void DrawBackground(CDC& dc, CRect& rect)

Override this function if you want different background drawing logic. The CRect rect parameter contains the dimensions of the control's client area

virtual void DrawBlock(CDC& dc, CRect& rect)

Override this function if you want to change the drawing logic of a standard block in the control
The CRect rect parameter contains the dimensions of the block being drawn

virtual void DrawHiliteBlock(CDC& dc, CRect& rect)

Override this function if you want to change the drawing logic of a highlighted block in the control
The CRect rect parameter contains the dimensions of the block being drawn

virtual void DrawPartialBlock(CDC& dc, CRect& rect)

Override this function if you want to change the drawing logic of a partially highlighted block in the control
The CRect rect parameter contains the dimensions of the block being drawn

... and the control responds to messages ...

The following messages are defined for interaction with the control via the SendMessage() or PostMessage() functions:

Message

WPARAM

LPARAM

Corresponding function

BPM_SETNUMSTEPS

Number of Steps (int)

N/A

SetNumSteps(int nNumSteps)

BPM_SETCURPOS

Current Marker Position(int)

N/A

SetCurPos(int nCurPos)

BPM_SETIBPAD

Interblock padding in pixels (int)

N/A

SetInterBlockPadding(int nPadding)

BPM_SETSPEED

Speed of busy mode in milliseconds (int)

N/A

SetSpeed(int nSpeed)

BPM_SETRANGE

Lower range of the progress bar (int)

Upper range of the progress bar (int)

SetRange(int& nLower, int& nUpper)

BPM_SETMODE

Mode of the control (int)

N/A

SetMode(int nMode)

BPM_STARTBUSY

N/A

N/A

Start()

BPM_ENDBUSY

N/A

N/A

End()

BPM_STEPIT

N/A

N/A

StepIt()

BPM_SETBUSYTYPE

Busy Mode Type (int)

N/A

SetBusyType(int nType)

BPM_SETBUSYFILL

Fill Type (int)

N/A

SetBusyFill(int nFill)

BPM_SETGRANULARITY

Granularity (int)

N/A

SetGranularity(int nGran)

BPM_SETCOLBKG

Colour (COLORREF)

N/A

SetColBkg(COLORREF col)

BPM_SETCOLBFACE

Colour (COLORREF)

N/A

SetColBlockFace(COLORREF col)

BPM_SETCOLBEDGE

Colour (COLORREF)

N/A

SetColBlockEdge(COLORREF col)

BPM_SETCOLBFACEHI

Colour (COLORREF)

N/A

SetColBlockFaceHi(COLORREF col)

BPM_SETCOLBEDGEHI

Colour (COLORREF)

N/A

SetColBlockEdgeHi(COLORREF col)

BPM_RECALC

N/A

N/A

Recalc()

BPM_RESET

N/A

N/A

Reset()

BPM_USESYSCOL

Flag (0 = false, non zero = true)

N/A

UseSysCol()

Known issues / To do List

  • Must implement an orientation flag to indicate horizontal or vertical display
  • Contemplating adding a tooltip to indicate "percentage" complete when the control is in BPC_MODE_PROGRESS mode

    Conclusion

    If you want an alternative to the stock standard Windows CProgressCtrl control, give this one a spin. Let me know if you like it Wink | ;)

    History

    Version

    Release Date

    Change Log

    0.3 2003-05-05
  • Added BPM_XXXXX messages for the outstanding "SetXXX()" functions. The message list above has been updated
  • Fixed an acute threading bug (thanks to luedi for this one)
  • 0.21 2003-04-30
  • Fixed the threading bug which occurred when you rapidly called Start() in succession. Thanks to Mark Richards for letting me know
  • 0.20 2003-04-22
  • Added support for WM_SYSCOLORCHANGE message
  • Added flag for whether background colour was a system colour (true by default)
  • Changed all ON_MESSAGE() handlers to return an LRESULT (compatibility issue with VC7)
  • Added "Busy Type" flag to support different motion while in busy mode. Supported modes are: BPC_BUSY_PINGPONG, BPC_BUSY_LTR and BPC_BUSY_RTL
  • Added "Busy Fill" flag to support different filling methods while in busy mode. Supported fill modes are: BPC_BUSYFILL_BLOCK and BPC_BUSYFILL_SMOOTH
  • Updated source and demo .zip files
  • Fixed small bug in percentage calculation of the progress bar.
  • 0.1 2003-04-21
  • First public release
  • <!------------------------------- That's it! --------------------------->
  • License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    About the Author

    Peter Mares
    Architect
    Ireland Ireland
    Peter Mares has no comment on himself. I'll let the objective humanoids do the damage Wink | ;)
    He is currently developing a hobby MMO to prove that he can do it Wink | ;)

    My Blog

    All good things were meant to be improved
    Follow on   Twitter

    Comments and Discussions

     
    GeneralRace Condition Problem leads to window handle problems / window flicker PinmemberForest-Andi19-Mar-09 23:37 
    GeneralRe: Race Condition Problem leads to window handle problems / window flicker PinmemberPeter Mares24-Sep-10 19:23 
    GeneralRe: Race Condition Problem leads to window handle problems / window flicker PinmemberLampengeist26-May-11 23:55 
    GeneralControl crashes when WaitForSingleObject returns nonsignaled PinmemberFrank1122334414-Feb-07 5:44 
    GeneralRe: Control crashes when WaitForSingleObject returns nonsignaled Pinmemberpeter_cheng_test7-Jul-09 0:11 
    GeneralThank you PinmemberFurno Gianluca2-Feb-06 22:36 
    QuestionHow to update busy progress bar in modeless dialog Pinmemberrnl@jk8-Jan-06 22:01 
    AnswerRe: How to update busy progress bar in modeless dialog PinmemberKonstantin Malanin29-Jan-07 12:02 
    GeneralSir! can you help me! Pinmemberilansue26-Oct-05 0:51 
    GeneralTransparent Background Pinsusswlburgess15-Oct-05 18:14 
    Great Job! Nice Control.
     
    I had need to paint the control over a textured Dialog background.
    I thought I'd share my code enhancements (not optimized):
     
    The following changes work if you select Transparency in the Extended Styles
    in the Dialog Editor for the Static control.
    Otherwise, the former background drawing occurs.
     
    In KCBusyProgressCtrl.h add:
         // drawing stuff
         CDC                    m_memHideDC;
         CBitmap                    m_memBmpHide;
         CBitmap*               m_pOldBmpHide;
     
    and
         // near DrawBlocks in the protected section
         void                        DrawBlocksMask(CDC& dc, CRect& rect);
     
    Now in KCBusyProgressCtrl.cpp add:
    In the constructor initialization:
    , m_pOldBmpHide(NULL)
     
    In the destructor:
         if ( m_pOldBmpHide )
         {
              m_memHideDC.SelectObject(m_pOldBmpHide);
              m_memBmpHide.DeleteObject();
              m_memHideDC.DeleteDC();
         }
     
    All of OnPaint and DrawBackground:
    void CKCBusyProgressCtrl::OnPaint()
    {
         CPaintDC               dc(this); // device context for painting
     
         // create a memory dc if needs be
         if ( !m_memDC.m_hDC )
         {
              m_memDC.CreateCompatibleDC(&dc);
              m_memBmp.CreateCompatibleBitmap(&dc, m_rect.Width(), m_rect.Height());
              m_pOldBmp = m_memDC.SelectObject(&m_memBmp);
         }
     
         // create another memory dc for Masking, if needs be
         if ( !m_memHideDC.m_hDC )
         {
              m_memHideDC.CreateCompatibleDC(&dc);
              m_memBmpHide.CreateCompatibleBitmap(&dc, m_rect.Width(), m_rect.Height());
              m_pOldBmpHide = m_memHideDC.SelectObject(&m_memBmpHide);
         }
     
         DrawBackground(m_memDC, m_rect);
         DrawBlocksMask(m_memHideDC, m_rect);
         DrawBlocks(m_memDC, m_rect);
     
         // render the final image
         if(!(GetExStyle() & WS_EX_TRANSPARENT))
         {
              dc.BitBlt(0, 0, m_rect.Width(), m_rect.Height(), &m_memDC, 0, 0, SRCCOPY);
         }
         else
         {
              dc.BitBlt(0, 0, m_rect.Width(), m_rect.Height(), &m_memHideDC, 0, 0, SRCAND);
              dc.BitBlt(0, 0, m_rect.Width(), m_rect.Height(), &m_memDC, 0, 0, SRCPAINT);
         }
    }
     
    /////////////////////////////////////////////////////////////////////////////
     
    void CKCBusyProgressCtrl::DrawBackground(CDC& dc, CRect& rect)
    {
         if(!(GetExStyle() & WS_EX_TRANSPARENT))
         {
              dc.FillSolidRect( &rect, m_colBkg );
         }
    }
     

    Plus one added member function:
    void CKCBusyProgressCtrl::DrawBlocksMask(CDC& dc, CRect& rect)
    {
         CRect                    bRect;
         double                    dXOffset = 0;
         int                         i;
         CPen                    nPen, *pOldPen = NULL;
         CBrush                    nBrush, *pOldBrush = NULL;
     
         dc.FillSolidRect( &rect, RGB(255, 255, 255) );
     
         // create some drawing tools
         nPen.CreatePen( PS_SOLID, 0, RGB(0, 0, 0) );
         nBrush.CreateSolidBrush( RGB(0, 0, 0) );
         pOldPen = dc.SelectObject(&nPen);
         pOldBrush = dc.SelectObject(&nBrush);
     
         // create the initial rectangle
         bRect.top = 0; bRect.bottom = (int) m_dBlockHeight;
         bRect.left = 0; bRect.right = (int) m_dBlockWidth;
         for ( i = 0; i < m_nNumSteps; i++ )
         {
              DrawBlock(dc, bRect);
     
              // offset the rectangle a bit
              dXOffset += m_dBlockWidth + (double) m_nIBPadding;
              bRect.left = (int) dXOffset;
              bRect.right = (int)(dXOffset + m_dBlockWidth);
         }
     
         // cleanup after ourselves...
         dc.SelectObject(pOldPen);
         dc.SelectObject(pOldBrush);
         nPen.DeleteObject();
         nBrush.DeleteObject();
    }
     
    Again, Thanks for sharing your Control Peter!
    Wayne

     
    Wayne L. Burgess
    TEN-K Computer Services Inc.

    GeneralProgress in a loop Pinmembercenturiansix5-Jun-05 20:22 
    GeneralRe: Progress in a loop PinmemberDavidCrow22-May-06 8:00 
    GeneralResizable progress bar PinmemberSamuele23-Mar-05 4:33 
    GeneralRe: Resizable progress bar PinmemberCatrick9-Jun-05 8:04 
    GeneralBusy bar won't terminate PinmemberCbenney0119-Aug-04 5:16 
    GeneralPossibly Dumb Question Pinmemberotrcomm11-Jul-04 12:18 
    GeneralRe: Possibly Dumb Question Pinmemberotrcomm11-Jul-04 14:50 
    GeneralRe: Possibly Dumb Question PinmemberPeter Mares12-Jul-04 8:34 
    GeneralRe: Possibly Dumb Question Pinmemberotrcomm13-Jul-04 6:53 
    GeneralGets my 5! PinmemberRobJones14-May-04 11:00 
    GeneralVery Impressive... PinmemberDoug Knudson3-Oct-03 10:16 
    GeneralRe: Very Impressive... Pinmemberdracon9-Dec-03 3:14 
    GeneralVertical progress bar PinmemberIv11-Jun-03 5:06 
    GeneralRational Purify error PinmemberShielsy104-Jun-03 0:33 
    GeneralRunning this outside of my app PinmemberTom Wright3-Jun-03 11:51 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Mobile
    Web03 | 2.8.140721.1 | Last Updated 5 May 2003
    Article Copyright 2003 by Peter Mares
    Everything else Copyright © CodeProject, 1999-2014
    Terms of Service
    Layout: fixed | fluid