Click here to Skip to main content
13,256,012 members (45,608 online)
Click here to Skip to main content
Add your own
alternative version


119 bookmarked
Posted 5 Mar 2009

A Simple Pie Chart Control

, 5 Mar 2009
Rate this:
Please Sign up or sign in to vote.
An article written in to describe a simple pie chart control implemented to be used in MFC applications.


This article is written to describe the simple pie chart control implemented for MFC applications. There are so many chart controls and libraries available online but some of them are lacking with regard to graphics or rich in graphics, and are a bit heavily used on small projects. This pie chart is written for the MFC platform using the graphics library GDI+ and simple in terms of classes used (single class) and the basic functionalities it provides. It has three styles of pie charts. They are:

  1. Doughnut style.
  2. Two dimensional style.
  3. Three dimensional style.

It consists of functionalities like setting colors to each pie chart elements, background and text areas. Setting up fonts for the texts, setting up rotations and setting inclination for 3-D style are also present.


The implementation uses the basic drawing functionalities in GDI+. But there are three properties which provide the visual qualities for the control. They are:

  1. Gradient calculation for the colors.
  2. Flicker-free drawing.
  3. Calculation for 3-D pie.

Calculating Gradient for Different Colors

It uses a simple linear calculation to find the gradient colors. Calculating the gradient for a given color was done as follows:

  1. Take RGB values separately for the given color.
  2. To calculate the dark gradient, they are divided by a common factor, later multiplied by a factor set by the user which will be equal or less than the division factor.

    Ex. for R value, R gradient = (R / division factor)* factor (linear equation)

  3. Then this value is subtracted from original R, calculating the R new value which creates a dark gradient value for the corresponding color.

For the division factor the value used is 255. The reason to choose 255 is that for any RGB value, the maximum it can get is 255.

To calculate the light gradient, each RGB values are subtracted from 255 and then divided by 255 to find the gradient.

This value is multiplied by a factor and added to original RGB values.

Color CPieChartWnd::CalculateGradientLight(Color crBase, float fGradVal)

	BYTE r = crBase.GetR();
	BYTE g = crBase.GetG();
	BYTE b = crBase.GetB();

	float fact = 255.0f;
	float rGrad = (255 - r) / fact;
	float gGrad = (255 - g) / fact;
	float bGrad = (255 - b) / fact;
	r =  BYTE(min(r + rGrad * fGradVal, 255));
	b =  BYTE(min(b + bGrad * fGradVal, 255));
	g =  BYTE(min(g + gGrad * fGradVal, 255));

	return Color(r, g, b);

Color CPieChartWnd::CalculateGradientDark(Color crBase, float fGradVal)

	BYTE r = crBase.GetR();
	BYTE g = crBase.GetG();
	BYTE b = crBase.GetB();

	float fact = 255.0f;
	float rGrad = r / fact;
	float gGrad = g / fact;
	float bGrad = b / fact;

	r = BYTE(max(r - rGrad * fGradVal, 0));
	b = BYTE(max(b - bGrad * fGradVal, 0));
	g = BYTE(max(g - gGrad * fGradVal, 0));

	return Color(r, g, b);

Flicker-free Drawing

The double buffering in GDI+ is done using the Bitmap and CachedBitmap objects. The way I used this is by creating a Graphics object using Graphics::FromImage. The Bitmap passed is created in the size of Cwnd area. Then all the drawing operations were done on the Graphics object. Finally this Graphics object is freed and the Bitmap is used in creating a CachedBitmap which will build from the graphics member created on device context. One technique is to save the Bitmap object and set it dirty on resizing or when the drawing changes. At other times the saved bitmap will be used directly on the CachedBitmap. But in this I only create and destroy the Bitmap when onPaint calls.

Bitmap* mBtmap = new Bitmap(rect.Width(), rect.Height());
graphics = Graphics::FromImage(mBtmap);

//rest of the drawings done on graphics object

delete graphics;
graphics = NULL;

Graphics gr(pDc->m_hDC);
CachedBitmap* btmp = new CachedBitmap(mBtmap, &gr);

if (mBtmap){
    delete mBtmap;
    mBtmap = NULL;
gr.DrawCachedBitmap(btmp, rect.left,;
if (btmp){
    delete btmp;
    btmp = NULL;

Calculation for 3-D Object

In the case of a 3-D pie chart, it has some transformation to do on its drawing parameters based on the inclination angle. So when the inclination angle is set, the circle pie shape goes to an elliptic shape resulting in visual changes in the element pie areas. These areas are transformed purely according to the changes in the pie angle per each element. This angle is calculated as follows:


So the calculation is:

New Point y' = y + x * sin (α). Using the new location of the point and the center point of the ellipse, the new angle α is calculated.

void CPieChartWnd::UpdatePiechartPoints(void)
	//The calculated pie element points are relocated according to the
         //incline angle and the resulting formations of angles were calculated and set.
	CRect rectBnd;
	//Calculate (set) the original locations for the points prior to the
         //circle it bounds.
	float flStart = fl_startAngle;
	float flStartIncline = 0;
	PointF ptStart;
	CRect rectBtm, rectTop;
	Get3DBounds(rectTop, rectBtm);

	long rectClip = long(fl_InclineAngle * rectBnd.Height() / 180); += long(rectClip * f_depth / 2);
	rectTop.bottom += long(rectClip * f_depth / 2);

	REAL xPoint = REAL(rectBnd.CenterPoint().x + 
				(rectBnd.Width() / 2) * cos(PI * (flStart)/ 180));
	REAL yPoint = REAL(rectBnd.CenterPoint().y + 
				(rectBnd.Height() / 2) * sin(PI * (flStart)/ 180));

	ptStart.X = xPoint;
	//Relocate the start angle y cordinate according to the inclination
	ptStart.Y = yPoint - REAL(rectClip * sin((flStart) * PI / 180));

	flStartIncline = CacluateInclineAngle(ptStart, rectTop);
	fl_startAngleIncline = flStartIncline;
	map<int, pie_chart_element*>::reverse_iterator iter = map_pChart.rbegin();
	//Relocate the y coordinates according to the incline angle and recalculate
         //the angles for elements
	for (; iter != map_pChart.rend(); iter++){
		pie_chart_element* ele = iter->second;
		ele->pie_3d_props.pt_InPie.Y -= REAL(
                      rectClip * sin((flStart + ele->f_angle) * PI / 180));
		float inClineAngle = CacluateInclineAngle(ele->pie_3d_props.pt_InPie,
		if(inClineAngle == flStartIncline && ele->f_angle == 360)
                  // Two points lies in the same location and the angle is 360
				inClineAngle = 360;	
		else if (inClineAngle >= flStartIncline)
				inClineAngle -= flStartIncline;
			inClineAngle += (360 - flStartIncline);
		ele->pie_3d_props.f_InclineAngle = inClineAngle;
		flStartIncline += inClineAngle;
		flStart += ele->f_angle;	

Using the Control

This control can be easily used by Creating a CPieChartwnd member on the Client Frame.

BOOL CPieChartWnd::Create(LPCTSTR lpCaption, const RECT& rect, CWnd* pParentWnd,
    UINT nID)

There are various functions provided to set visual qualities like colors, pie style, fonts and color gradients. By setting up start angle in timers can create rotating effects and setting up incline angle can create inclination effects on 3-D style chart. Also it has some functionality to sort the elements and to reverse back to the added order.

Pie chart element structure

struct pie_3d_properties{
	float f_InclineAngle; //The transformed angle for 3-D pie chart
	PointF pt_InPie;	    //The location point for a single element on the face
                               //of pie
	GraphicsPath path;	    //The visible path object from  side view

struct pie_chart_element{
		double d_value;
		float f_percentage;
		float f_angle;	
		float f_ColorGradL;
		float f_ColorGradD;
		Color cr_GradientL;
		Color cr_GradientD;
		Color cr_Base;
		CString s_label;
		CString s_element;
		pie_3d_properties pie_3d_props;
		int i_ID;
		BOOL b_select;

The pie chart element has two unique keys. One is a string key which users can define when an element is added. Another one is an integer identifier. This is added by the control it self. The string key has to be unique and not an empty string.

Add element:

The method InsertItem is defined to add elements to the chart. If the insertion was succeeded, it will return a pointer to the element which is the defined data type for the pie_chart_element. The return pointer is in type PIECHARTITEM

Removal of elements can be done using the two keys or using a PIECHARTITEM pointer

PIECHARTITEM InsertItem(CString sElement, CString sLabel, double dValue, Color crColor);
//Remove item functions
BOOL RemoveItem(CString sElement);
BOOL RemoveItem(int iElementID);

Points of Interest

This control provides only basic functionalities which a pie chart control should hold but it will be useful for small MFC applications. Also this might help as a learning material for GDI+ graphics too.


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


About the Author

Canada Canada
Prasad Perera is a software developer who's interested in parallel and distributed computing and graphics programming!

Currently he is following his masters in Concordia University, Montreal.

You may also be interested in...


Comments and Discussions

QuestionDamn cool Pin
wei-sun-ding15-Jun-12 1:17
memberwei-sun-ding15-Jun-12 1:17 
Questionnice work Pin
xunonxyz27-Apr-12 19:05
memberxunonxyz27-Apr-12 19:05 
GeneralMy vote of 5 Pin
Abu Mami22-Jul-11 1:33
memberAbu Mami22-Jul-11 1:33 
GeneralRe: My vote of 5 Pin
PrasadPerera24-Jul-11 10:36
memberPrasadPerera24-Jul-11 10:36 
GeneralMy vote of 5 Pin
François Gasnier4-Jan-11 1:56
memberFrançois Gasnier4-Jan-11 1:56 
GeneralRe: My vote of 5 Pin
PrasadPerera4-Jan-11 8:05
memberPrasadPerera4-Jan-11 8:05 
GeneralNeed Help regarding the inclination angle calculation Pin
Deepak.M14-Oct-09 7:11
memberDeepak.M14-Oct-09 7:11 
i need the help regarding the inclination angle calculation part for this example.

and also do u have the above piechat code return in or can u attach to this blog it will be vermuch helpfull for us

GeneralRe: Need Help regarding the inclination angle calculation Pin
PrasadPerera17-Oct-09 21:47
memberPrasadPerera17-Oct-09 21:47 
GeneralImproved 3-D pie chart Pin
PrasadSRCSE21-Apr-09 11:28
memberPrasadSRCSE21-Apr-09 11:28 
Generalwell done Pin
abo hashem21-Apr-09 2:37
memberabo hashem21-Apr-09 2:37 
GeneralRe: well done Pin
PrasadSRCSE21-Apr-09 11:25
memberPrasadSRCSE21-Apr-09 11:25 
Generalsome bugs happens when i change the project from unicode to multi-byte; Pin
yejiang1258-Apr-09 0:14
memberyejiang1258-Apr-09 0:14 
GeneralRe: some bugs happens when i change the project from unicode to multi-byte; Pin
PrasadSRCSE8-Apr-09 12:50
memberPrasadSRCSE8-Apr-09 12:50 
GeneralBuild Error error C2660 Pin
samal.subhashree30-Mar-09 3:30
membersamal.subhashree30-Mar-09 3:30 
GeneralRe: Build Error error C2660 Pin
PrasadSRCSE30-Mar-09 8:18
memberPrasadSRCSE30-Mar-09 8:18 
GeneralRe: Build Error error C2660 Pin
samal.subhashree30-Mar-09 18:03
membersamal.subhashree30-Mar-09 18:03 
GeneralRe: Build Error error C2660 Pin
PrasadSRCSE31-Mar-09 5:24
memberPrasadSRCSE31-Mar-09 5:24 
GeneralRe: Build Error error C2660 Pin
samal.subhashree31-Mar-09 18:25
membersamal.subhashree31-Mar-09 18:25 
GeneralRe: Build Error error C2660 Pin
PrasadSRCSE31-Mar-09 18:31
memberPrasadSRCSE31-Mar-09 18:31 
GeneralRe: Build Error error C2660 Pin
samal.subhashree1-Apr-09 1:57
membersamal.subhashree1-Apr-09 1:57 
GeneralRe: Build Error error C2660 Pin
PrasadSRCSE1-Apr-09 7:32
memberPrasadSRCSE1-Apr-09 7:32 
GeneralRe: Build Error error C2660 Pin
samal.subhashree1-Apr-09 22:02
membersamal.subhashree1-Apr-09 22:02 
GeneralUnable to Use 3D Pie Pin
samal.subhashree25-Mar-09 3:39
membersamal.subhashree25-Mar-09 3:39 
GeneralRe: Unable to Use 3D Pie Pin
PrasadSRCSE25-Mar-09 9:13
memberPrasadSRCSE25-Mar-09 9:13 
GeneralRe: Unable to Use 3D Pie Pin
samal.subhashree28-Mar-09 1:36
membersamal.subhashree28-Mar-09 1:36 
GeneralRe: Unable to Use 3D Pie Pin
PrasadSRCSE28-Mar-09 4:05
memberPrasadSRCSE28-Mar-09 4:05 
GeneralRe: Unable to Use 3D Pie Pin
samal.subhashree30-Mar-09 0:25
membersamal.subhashree30-Mar-09 0:25 
GeneralRe: Unable to Use 3D Pie Pin
PrasadSRCSE30-Mar-09 7:49
memberPrasadSRCSE30-Mar-09 7:49 
GeneralBuild Error in PieChartWnd.cpp Pin
Gilles Ngainsi21-Mar-09 5:51
memberGilles Ngainsi21-Mar-09 5:51 
GeneralRe: Build Error in PieChartWnd.cpp [modified] Pin
PrasadSRCSE21-Mar-09 7:22
memberPrasadSRCSE21-Mar-09 7:22 
GeneralGreat Job Pin
Ram Jawahar Pandey9-Mar-09 2:48
memberRam Jawahar Pandey9-Mar-09 2:48 
GeneralRe: Great Job Pin
PrasadSRCSE9-Mar-09 7:27
memberPrasadSRCSE9-Mar-09 7:27 
GeneralRe: Great Job Pin
Mukade13-Mar-09 4:40
memberMukade13-Mar-09 4:40 
QuestionDo you knonw this artical? Pin
chenyu22028638-Mar-09 16:13
memberchenyu22028638-Mar-09 16:13 
AnswerRe: Do you knonw this artical? Pin
PrasadSRCSE8-Mar-09 18:44
memberPrasadSRCSE8-Mar-09 18:44 
GeneralRe: Do you knonw this artical? Pin
chenyu22028639-Mar-09 5:42
memberchenyu22028639-Mar-09 5:42 
GeneralRe: Do you knonw this artical? Pin
PrasadSRCSE9-Mar-09 7:26
memberPrasadSRCSE9-Mar-09 7:26 
GeneralIt looks great Pin
Tage Lejon8-Mar-09 9:39
memberTage Lejon8-Mar-09 9:39 
GeneralRe: It looks great Pin
PrasadSRCSE8-Mar-09 18:46
memberPrasadSRCSE8-Mar-09 18:46 
GeneralGood Pin
chenyu22028637-Mar-09 19:39
memberchenyu22028637-Mar-09 19:39 
GeneralRe: Good Pin
PrasadSRCSE7-Mar-09 19:54
memberPrasadSRCSE7-Mar-09 19:54 

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

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

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171114.1 | Last Updated 5 Mar 2009
Article Copyright 2009 by PrasadPerera
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid