Introduction
I have been looking for a pie control that would use the skin images instead of simple colors and just could not find that. And I struggled quite a lot to make it but ..:( anyway so found out another solution that is 3D pie control that could satisfy my needs. I got it developed with one of my bright colleagues, Amit Ganguly, who is a fresh engineer and strong with mathematics. So guys, just download it, use it, and let me know your comments.
How to Use It
This is very simple to use. Just add a button to your project and make member variables of the button. Include the following line at the top of the dialog box's header file (if you are making a dialog box based application as my demo project with the article).
#include "PieProgress.h"
Now you have included the class CPieProgress
. It's time to make an object of this class, change the following code in the header file.
CButton m_ctlPieProgress;
to:
CPieProgress m_ctlPieProgress;
Of course, if the member variable of the button earlier created by you, is named m_ctlPieProgress
. All is done, all you have to do now is initialize the pie control. Add the following lines of code in your dialog box's implementation class in the function OnInitDialog()
.
BOOL CPieControlDlg::OnInitDialog()
{
CDialog::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE);
m_ctlPieProgress.SetRange(0,100);
m_ctlPieProgress.SetProgressColors(RGB(255,0,0),RGB(0,255,0));
SetTimer(1978,500,NULL);
return TRUE; }
I have set a timer here to see the progress. So it's all done and you have a 3D-pie control in your project. Enjoy.........
Behind the Scenes
Nothing magical here. It's the magic of subclassing. I derived the pie control's class directly from CWnd
and have the magical drawing function DrawPie()
get called from OnPaint()
after checking that the progress value lies in the range set as follows:
void CPieProgress::DrawPie(CZipDC * pDC,CPoint CntrPt,CRect Rect)
{
CBrush BkgndBrh;
CBrush FrgndBrh;
BkgndBrh.CreateSolidBrush(clrComplete);
FrgndBrh.CreateSolidBrush(clrIncomplete);
iSemi_ht = 0.6 * Rect.Height() /2;
iSemi_lt = Rect.Width()/2;
PieRect.top = CntrPt.y - iSemi_ht;
PieRect.bottom = CntrPt.y + iSemi_ht;
PieRect.left = CntrPt.x - iSemi_lt;
PieRect.right = CntrPt.x + iSemi_lt;
StrtPt.x = CntrPt.x;
StrtPt.y = CntrPt.y + iSemi_ht;
EndPt = StrtPt;
pDC->SelectObject(&BkgndBrh);
pDC->Pie(PieRect.operator LPRECT(),StrtPt,EndPt);
iPer = ((nValue - nLow)* 100/(nHigh - nLow));
EndPt = GetPerPoint(iPer,iSemi_lt,iSemi_ht,CntrPt);
pDC->SelectObject(&FrgndBrh);
pDC->Pie(PieRect.operator LPRECT(),StrtPt,EndPt);
Rect_1.bottom = CntrPt.y;
Rect_1.right = CntrPt.x;
Rect_1.top = CntrPt.y - 10;
Rect_1.left = CntrPt.x - iSemi_lt;
Rect_2.top = CntrPt.y - 10;
Rect_2.left =CntrPt.x;
Rect_2.bottom = CntrPt.y;
Rect_2.right = CntrPt.x + iSemi_lt;
if(iPer >= 25)
{
pDC->FillRect(Rect_1.operator LPRECT(),&BkgndBrh);
if(iPer >= 75)
{
pDC->FillRect(Rect_2.operator LPRECT(),&BkgndBrh);
}
else
{
pDC->FillRect(Rect_2.operator LPRECT(),&FrgndBrh);
}
}
else
{
pDC->FillRect(Rect_1.operator LPRECT(),&FrgndBrh);
pDC->FillRect(Rect_2.operator LPRECT(),&FrgndBrh);
}
if(iPer <= 50)
{
Rect_1.bottom = EndPt.y;
switch(iPer)
{
case 0:
Rect_1.right = EndPt.x ;
break;
case 1:
Rect_1.right = EndPt.x + 2;
break;
case 2:
Rect_1.right = EndPt.x + 4;
break;
case 3:
Rect_1.right = EndPt.x + 6;
break;
case 4:
Rect_1.right = EndPt.x + 8;
break;
default:
Rect_1.right = EndPt.x + 10;
break;
}
Rect_1.top = EndPt.y - 10;
Rect_1.left = EndPt.x;
pDC->FillRect(Rect_1.operator LPRECT(),&BkgndBrh);
}
else
{
Rect_1.bottom = EndPt.y;
switch(iPer)
{
case 96:
Rect_1.left = EndPt.x - 8;
break;
case 97:
Rect_1.left = EndPt.x - 6;
break;
case 98:
Rect_1.left = EndPt.x - 4;
break;
case 99:
Rect_1.left = EndPt.x - 2;
break;
case 100:
Rect_1.left = EndPt.x ;
break;
default:
Rect_1.left = EndPt.x - 10;
break;
}
Rect_1.top = EndPt.y - 10;
Rect_1.right = EndPt.x;
pDC->FillRect(Rect_1.operator LPRECT(),&FrgndBrh);
}
CntrPt.y = CntrPt.y - 10;
PieRect.top = CntrPt.y - iSemi_ht;
PieRect.bottom = CntrPt.y + iSemi_ht ;
PieRect.left = CntrPt.x - iSemi_lt;
PieRect.right = CntrPt.x + iSemi_lt;
StrtPt.x = CntrPt.x;
StrtPt.y = CntrPt.y + iSemi_ht;
EndPt = StrtPt;
pDC->SelectObject(&BkgndBrh);
pDC->Pie(PieRect.operator LPRECT(),StrtPt,EndPt);
EndPt = GetPerPoint(iPer,iSemi_lt,iSemi_ht,CntrPt);
pDC->SelectObject(&FrgndBrh);
pDC->Pie(PieRect.operator LPRECT(),StrtPt,EndPt);
pDC->MoveTo(CntrPt.x - iSemi_lt,CntrPt.y);
pDC->LineTo(CntrPt.x - iSemi_lt,CntrPt.y + 10);
pDC->MoveTo(CntrPt.x + iSemi_lt,CntrPt.y);
pDC->LineTo(CntrPt.x + iSemi_lt,CntrPt.y + 10);
}
Now you must be wondering why so much of code there. Well, this is what shows Mr. Amit Ganguly's mathematical skills. I haven't really checked what all he has written there but I think, this must be the smallest code required to draw the pie (I guess it is called Keplar's law).
Guys Help Me
Please let me know if someone has any idea about the skin based pie control...coool...so just live life ;)
History
- 27th October, 2002: Initial version
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below. A list of licenses authors might use can be found here.
innovating, managing and developing next generation media products and services