Environment: [VC6]
This is a progress bar control that uses icons.
First create a static control of the required size in the dialog editor
and set the style you want.
The ‘Attach’ function sets up the following features:
- The icon to use in the progress bar.
- The number of pixels to increment between each icon.
- The background colour. (Optional, the default is the 3D face colour)
- The stagger value. (Optional, the default is zero)
This is the number of pixels that the icons will be offset each time, creating a zigzag pattern.
‘Attach’ will calculate the number of icons that can be contained within
the static control and attempt to centralise the bar within it.
It will derive the orientation of the bar by using the aspect ratio
of the control.
‘SetIconChange’ allows you to modify the icon that will be displayed from
a certain value.
Example
// ICON1 for the whole bar, increment of 4, pale // blue background, stagger of 2 Attach( IDC_ICON_PROGRESS, this, IDI_ICON1, 4, RGB(128, 128, 255), 2); SetRange(0, 100); SetPos(0); // Use icon 2 from position 10 to 100 SetIconChange(IDI_ICON2, 10); // Use icon 3 from position 30 to 100 SetIconChange(IDI_ICON3, 30); // Use icon 4 from position 70 to 100 SetIconChange(IDI_ICON4, 70);
Final result
0 - 9 = ICON1 10 - 29 = ICON2 30 - 69 = ICON3 70 - 100 = ICON4
The acuracy of the changeover position will depend on the number total of icons
displayed for the range.
i.e.
If, in the above example, there were only 6 icons in total, the changeover position of 30 should occur at 1.78 icons. This of course can’t happen so the changeover icon index will be rounded down to 1. This equates to a position of 17.
The more icons you can fit into the bar the more accurate it will be.
CIconProgress supports all of the normal CProgressCtrl member functions.
///////////////////////////////////////////////
// CIconProgress windowclass CIconProgress : public CWnd
{
// Construction
public:
CIconProgress();void Attach(UINT control_id,
CWnd *parent,
UINT icon_id,
int increment,
int stagger = 0);void Attach(UINT control_id,
CWnd *parent,
UINT icon_id,
int increment,
COLORREF background,
int stagger = 0);void SetRange(short lower,
short upper);void SetRange32(int lower,
int upper);void GetRange(int &lower,
int &upper);int SetPos(int position);
int GetPos();
int OffsetPos(int offset);
int SetStep(int step);
int StepIt();
void SetIconChange(UINT icon_id, int position);
// Attributes
public:// Operations
public:// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CIconProgress)
//}}AFX_VIRTUAL// Implementation
public:
virtual ~CIconProgress();private:
int GetNumberOfIcons(int position);static const int HORIZONTAL;
static const int VERTICAL;CBrush background_brush;
HICON hicon;
COLORREF background_colour;
int icon_increment;
int orientation;
int total_number_of_icons;
int number_of_icons;
int icon_major;
int icon_minor;
int window_major;
int window_minor;
int start_major;
int start_minor;
int stagger_distance;
int upper;
int lower;
int position;
int step;
RECT window_rect;CArray
hicon_array; // Generated message map functions
protected:
//{{AFX_MSG(CIconProgress)
afx_msg void OnPaint();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};// Constants
const int CIconProgress::HORIZONTAL = 0;
const int CIconProgress::VERTICAL = 1;// Message map
BEGIN_MESSAGE_MAP(CIconProgress, CWnd)
//{{AFX_MSG_MAP(CIconProgress)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()//////////////////////////////////////////
// ConstructorCIconProgress::CIconProgress()
{
upper = 100;
lower = 0;
position = 0;
step = 10;
}//////////////////////////////////////////
// DestructorCIconProgress::~CIconProgress()
{
background_brush.DeleteObject();
}//////////////////////////////////////////
// SetInitial – default colourvoid CIconProgress::Attach( UINT control_id,
CWnd *parent,
UINT icon_id,
int increment,
int stagger)
{
Attach( control_id,
parent,
icon_id,
increment,
GetSysColor(COLOR_3DFACE),
stagger);
}//////////////////////////////////////////
// SetInitial – specified colourvoid CIconProgress::Attach( UINT control_id,
CWnd *parent,
UINT icon_id,
int increment,
COLORREF background,
int stagger)
{
SubclassDlgItem(control_id, parent);// Store the parameters.
icon_increment = increment;
background_colour = background;
stagger_distance = stagger;// Create the background brush.
background_brush.CreateSolidBrush(background_colour);// Get the icon handle.
hicon = AfxGetApp()->LoadIcon(icon_id);// Find the client window size.
GetClientRect(&window_rect);// Set the orientation and the major and minor axis.
// Major is in the direction of progress.
if (window_rect.right > window_rect.bottom)
{
orientation = HORIZONTAL;
}
else
{
orientation = VERTICAL;
}switch (orientation)
{
case HORIZONTAL:
{
icon_major = GetSystemMetrics(SM_CXICON);
icon_minor = GetSystemMetrics(SM_CYICON);
window_minor = window_rect.bottom;
window_major = window_rect.right;
break;
}case VERTICAL:
{
icon_minor = GetSystemMetrics(SM_CXICON);
icon_major = GetSystemMetrics(SM_CYICON);
window_major = window_rect.bottom;
window_minor = window_rect.right;
break;
}
}// Adjust for daft icon increment.
if (icon_increment == 0)
{
icon_increment = 1;
}// Find the number of icons that will fit in the window.
total_number_of_icons = 1;
while (((total_number_of_icons * icon_increment)
+ icon_major) < window_major)
{
total_number_of_icons++;
}// Fill the icon array with the default icon
hicon_array.SetSize(total_number_of_icons);
for (int i = 0; i < total_number_of_icons; i++)
{
hicon_array[i] = hicon;
}// Find the start points.
switch (orientation)
{
case HORIZONTAL:
{
// Left.
start_major = (window_major –
(((total_number_of_icons – 1)
* icon_increment)
+ icon_major)) / 2;
break;
}case VERTICAL:
{
// Bottom.
start_major = ((window_major
+ (((total_number_of_icons – 1)
* icon_increment) + icon_major)) / 2)
– icon_major;
}
}start_minor = (window_minor –
icon_minor –
stagger_distance) / 2;
}//////////////////////////////////////////
// SetPosint CIconProgress::SetPos(int new_position)
{
int old_position;old_position = position;
position = new_position;
position = min(upper, max(lower, position));
number_of_icons = GetNumberOfIcons(position);Invalidate();
return old_position;
}//////////////////////////////////////////
// OffsetPosint CIconProgress::OffsetPos(int offset)
{
int old_position;old_position = position;
position += offset;
position = min(upper, max(lower, position));
number_of_icons = GetNumberOfIcons(position);Invalidate();
return old_position;
}//////////////////////////////////////////
// SetRangevoid CIconProgress::SetRange(short lower_range,
short upper_range)
{
SetRange32(lower_range, upper_range);
}//////////////////////////////////////////
// SetRange32void CIconProgress::SetRange32( int lower_range,
int upper_range)
{
lower = lower_range;
upper = upper_range;
position = min(upper, max(lower, position));
number_of_icons = GetNumberOfIcons(position);Invalidate();
}//////////////////////////////////////////
// SetIconChangevoid CIconProgress::SetIconChange( UINT icon_id,
int position)
{
HICON hicon = AfxGetApp()->LoadIcon(icon_id);// Where to start from
int change_icon_index = GetNumberOfIcons(position);// Fill part of the array with the new icon
for ( int i = change_icon_index;
i < total_number_of_icons;
i++)
{
hicon_array[i] = hicon;
}
}//////////////////////////////////////////
// SetStepint CIconProgress::SetStep(int new_step)
{
int old_step;old_step = step;
step = new_step;return old_step;
}//////////////////////////////////////////
// StepItint CIconProgress::StepIt()
{
int old_position;old_position = position;
position += step;
position = min(upper, max(lower, position));
number_of_icons = GetNumberOfIcons(position);Invalidate();
return old_position;
}//////////////////////////////////////////
// GetPosint CIconProgress::GetPos()
{
return position;
}//////////////////////////////////////////
// GetRangevoid CIconProgress::GetRange(int &lower_range,
int &upper_range)
{
lower_range = lower;
upper_range = upper;
}//////////////////////////////////////////
// GetNumberOfIconsint CIconProgress::GetNumberOfIcons(int position)
{
int n_icons;
float delta = (float)(position – lower);
float range = (float)(upper – lower + 1);float range_per_icon = range / total_number_of_icons;
// Just in case of rounding errors
if (position == upper)
{
n_icons = total_number_of_icons;
}
else
{
n_icons = (int)(delta / range_per_icon);
}return n_icons;
}//////////////////////////////////////////
// CIconProgress message handlersvoid CIconProgress::OnPaint()
{
CPaintDC dc(this);
CDC memdc;
CBitmap bitmap;
int x, y, count;
BOOL do_stagger = FALSE;// Create a memory copy to draw to.
memdc.CreateCompatibleDC(&dc);
bitmap.CreateCompatibleBitmap(&dc,
window_rect.right,
window_rect.bottom);
memdc.SelectObject(&bitmap);// Clear the background.
memdc.FillRect(&window_rect, &background_brush);// Draw the icons.
switch (orientation)
{
case HORIZONTAL:
{
for ( x = start_major,
count = 0; count < number_of_icons;
x += icon_increment, count++)
{
if (do_stagger)
{
memdc.DrawIcon(x,
start_minor + stagger_distance,
hicon_array[count]);
}
else
{
memdc.DrawIcon(x, start_minor, hicon_array[count]);
}do_stagger = !do_stagger;
}
break;
}case VERTICAL:
{
for ( y = start_major, count = 0;
count < number_of_icons;
y -= icon_increment, count++)
{
if (do_stagger)
{
memdc.DrawIcon(start_minor +
stagger_distance,
y,
hicon_array[count]);
}
else
{
memdc.DrawIcon(start_minor,
y,
hicon_array[count]);
}do_stagger = !do_stagger;
}
break;
}
}// Copy it to the screen.
dc.BitBlt( 0, 0,
window_rect.right,
window_rect.bottom,
&memdc,
0, 0,
SRCCOPY);// Delete the tempory resources.
memdc.DeleteDC();
bitmap.DeleteObject();
}BOOL CIconProgress::OnEraseBkgnd(CDC* pDC)
{
// Indicate that it is already erased.
return TRUE;
}