Page 1 of 1

C++ Windows Charting Library Part 2 Rate Topic: ***** 1 Votes

#1 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 777
  • View blog
  • Posts: 2,297
  • Joined: 20-March 10

Posted 03 January 2013 - 09:35 AM

C++ Windows Charting Library Part 2

In Part two we are going to go over the Bar Chart Making Part of the Library.

In ChartKM.h

//Draws Bar Chart
	void DrawBar(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor);

.......................

//Adds Group Data for Bar and Line Charts
	void AddGroupData(string nmGroup, COLORREF color);
	// Adds Item Data for Bar Charts
	void AddItemData(string nmItem, float value, int GroupNo);

.......................

// Get Total for Bars
	void GetTotalBar();
    // Get Amount of Groups for Bars
	void GetGroupBar();
	// Get Largest Amount Of Item Data for Bars
	void GetLargestBar();



DrawBar draws the bar chart at x and y with size szBarX width and szBarY high with specified color.

Add-group-data and Add-item-data add the information first the groups on how to classify data with specified color

This will group the data for the items which is a string and a float value.

GetTotalBar adds the totals and GetGroupBar gets the amount of groups there are while GetLargestBar gives us the biggest bar out of all the data this will also be our limit and also will determine the height of the other bars as a percentage of this bar.


A bar chart is a chart that uses either horizontal or vertical bars to show comparisons among groups. One axis of the chart shows the specific groups being compared, and the other axis represents a discrete value. Some bar graphs present bars clustered in groups of more than one (grouped bar graphs), and others show the bars divided into subparts to show cumulative effect (stacked bar graphs). How to use it: Determine the discrete range.


ChartKM.cpp

void chartObject::AddGroupData(string nmGroup, COLORREF color)
{
	GroupName.push_back(nmGroup);
	colors.push_back(color);
}

void chartObject::AddItemData(string nmItem, float value, int GroupNo)
{
	ItemName.push_back(nmItem);
	ItemValue.push_back(value);
	ItemGroup.push_back(GroupNo);
}
void chartObject::SetAxisTitles(string szAxisX, string szAxisY)
{
	xName.assign(szAxisX);
	yName.assign(szAxisY);

}

void chartObject::GetTotalBar()
{
	for(unsigned i = 0; i<ItemValue.size(); i++)
	{
		ValueItem = ValueItem+ItemValue[i];
	}

	ValueItem = ValueItem / (ItemValue.size()+1);
}

void chartObject::GetGroupBar()
{
	FreqBar = GroupName.size();

}

void chartObject::GetLargestBar()
{
	LargestBar  = ItemValue[0];
	for(unsigned i =1; i<ItemValue.size(); i++)
	{
		if(LargestBar<ItemValue[i])
		{
			LargestBar = ItemValue[i];
		}
	}

}


void chartObject::DrawBar(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor)
{
	HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
	SelectObject(hdcDst,pen);
	HFONT font;
	//Set Background Color for Text
	SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
	font = CreateFont(14,0,900,900,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
		CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
	SelectObject(hdcDst, font);
	//Draw y axis
	MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
	LineTo(hdcDst,x+25+14,y);
	//Draw x axis
	MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
	LineTo(hdcDst,szBarX+x+25+14,(szBarY)+y);

	TextOut(hdcDst,x,((szBarY+y/2)+(yName.length()/2)),yName.c_str(),yName.length());// Draw y-axis label
	font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
		CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
	SelectObject(hdcDst, font);
	TextOut(hdcDst,((szBarX-x)/2)-(xName.length()/2),y+szBarY+42,xName.c_str(),xName.length());//Draw x-axis label
	TextOut(hdcDst,x+(25),y+szBarY,"0",1);// Draw a zero at origin

	TextOut(hdcDst,((szBarX-x)/2)-(Title.length()/2),y-24,Title.c_str(),Title.length());//Draw Title

	//Get Totals for Bar Chart
	GetTotalBar();
	GetGroupBar();
	GetLargestBar();

	//Draw Graph
	Units = LargestBar/3.0f;
	int graph = szBarY/3;
	for(int i = 0; i<3; i++)
	{
		MoveToEx(hdcDst,x+25+14,(graph*i)+y,NULL);
		LineTo(hdcDst,x+25+14+szBarX+5,(graph*i)+y);
		stringstream  number;
		number << setprecision(3);
		number << (LargestBar-(Units*i));
		string num = "";
		number >> num;
		TextOut(hdcDst,x+25+14+szBarX+7,(graph*i)+y,num.c_str(),num.length());//draw numbers

	}
	for(unsigned i= 0; i<GroupName.size(); i++)
	{
		//draw Legend
		Rectangle(hdcDst,(x+50-12-1),y+szBarY+42+(25*(i+1)-1),(x+50-12-1+12),y+szBarY+42+(25*(i+1)+12));
		RECT rc;
		rc.left= (x+50-12);
		rc.top = y+szBarY+42+(25*(i+1));
		rc.right = (x+50)-2;
		rc.bottom = y+szBarY+42+(25*(i+1)+12)-1;
		HBRUSH hbr = CreateSolidBrush(colors[i]);

		FillRect(hdcDst,&rc,hbr);
		TextOut(hdcDst,(x)+(GroupName[i].length()+50),y+szBarY+42+(25*(i+1)),GroupName[i].c_str(),GroupName[i].length());//Drawlabels


	}
	MoveToEx(hdcDst,x+25+14+szBarX,(y+szBarY),NULL);
	LineTo(hdcDst,x+25+14+szBarX,(y+szBarY+15));
	MoveToEx(hdcDst,x+25+14+szBarX,y,NULL);
	LineTo(hdcDst,x+25+14+szBarX,y+szBarY);
	int amt = (ItemValue.size())/(GroupName.size());
	int sections = (szBarX)/amt;
	int counter = 0;
	int count = 0;
	// Draw Bar Data
	for(unsigned i =0; i<(ItemValue.size()); i=i+GroupName.size())
	{
		counter = (i/GroupName.size())* sections;
		MoveToEx(hdcDst,x+25+14+counter,(y+szBarY),NULL);
		LineTo(hdcDst,x+25+14+counter,(y+szBarY+15));
		TextOut(hdcDst,(x+25+14+counter)+(ItemName[i].length()),(y+szBarY+15),ItemName[i].c_str(),ItemName[i].length());



		for(unsigned j = 0; j<(GroupName.size()); j++)
		{
			RECT rect;
			float result = szBarY-(szBarY*(ItemValue[count]/LargestBar))+y;
			rect.bottom = y+szBarY;
			rect.right =  x+25+14+counter+5+((szBarX/20)*(j+1));
			rect.top =  (LONG)(result);
			rect.left = (x+25+14+counter+5+((szBarX/20)*j));

			HBRUSH hbr = CreateSolidBrush(colors[j]);
			FillRect(hdcDst,&rect,hbr);
			count++;

		}
	}
	DeleteObject(pen);
	DeleteObject(font);
}




We have went over the helper functions AddGroupData and AddItemData already so now for the DrawBar function.

We create a pen and a font select it into the dc.

Draw the x-axis and the y-axis.

Draw the corresponding labels for both axis.

GetTotalBar();
GetGroupBar();
GetLargestBar();


These helper functions we have went over.

We now draw our graph.

We split the graph into 3 sections

We draw our graph complete with numbers down the side.

We then draw the Legend according to how many groups there are.

We now draw the actual bar data.

We do this by having two loops, one for the amount of groups and one for the amount of bar data.

We loop through populating the graph.

Next an example program on its use.

#include <Windows.h>
#include <ChartKM.h>

#pragma comment(lib, "ChartKM.lib")


chartObject Chart;


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "PieChart";

int WINAPI WinMain (HINSTANCE hThisInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpszArgument,
	int nCmdShow)
{
	HWND hwnd;               /* This is the handle for our window */
	MSG messages;            /* Here messages to the application are saved */
	WNDCLASSEX wincl;        /* Data structure for the windowclass */

	/* The Window structure */
	wincl.hInstance = hThisInstance;
	wincl.lpszClassName = szClassName;
	wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
	wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
	wincl.cbSize = sizeof (WNDCLASSEX);

	/* Use default icon and mouse-pointer */
	wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
	wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
	wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
	wincl.lpszMenuName = NULL;                 /* No menu */
	wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
	wincl.cbWndExtra = 0;                      /* structure or the window instance */
	/* Use Windows's default colour as the background of the window */
	wincl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);

	/* Register the window class, and if it fails quit the program */
	if (!RegisterClassEx (&wincl))
		return 0;

	/* The class is registered, let's create the program*/
	hwnd = CreateWindowEx (
		0,                   /* Extended possibilites for variation */
		szClassName,         /* Classname */
		"Charting Demo Application.",       /* Title Text */
		WS_OVERLAPPEDWINDOW, /* default window */
		CW_USEDEFAULT,       /* Windows decides the position */
		CW_USEDEFAULT,       /* where the window ends up on the screen */
		1100,                 /* The programs width */
		550,                 /* and height in pixels */
		HWND_DESKTOP,        /* The window is a child-window to desktop */
		NULL,                /* No menu */
		hThisInstance,       /* Program Instance handler */
		NULL                 /* No Window Creation data */
		);

	/* Make the window visible on the screen */
	ShowWindow (hwnd, nCmdShow);

	/* Run the message loop. It will run until GetMessage() returns 0 */
	while (GetMessage (&messages, NULL, 0, 0))
	{
		/* Translate virtual-key messages into character messages */
		TranslateMessage(&messages);
		/* Send message to WindowProcedure */
		DispatchMessage(&messages);
	}

	/* The program return-value is 0 - The value that PostQuitMessage() gave */
	return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{


	switch (message)                  /* handle the messages */
	{
	case WM_CREATE:
		{


		Chart.AddTitle("Traffic Survey High Street, Kirby");
		Chart.SetAxisTitles("Vehicles", "Amount Per Hour");
		Chart.AddGroupData("2003",RGB(0,0,255));
		Chart.AddGroupData("2005",RGB(255,0,0));
		Chart.AddGroupData("2007",RGB(0,255,0));
		Chart.AddItemData("Cars",140.0f,1);
		Chart.AddItemData("Cars",150.0f,2);
		Chart.AddItemData("Cars",140.0f,3);
		Chart.AddItemData("Vans",40.0f,1);
		Chart.AddItemData("Vans",35.0f,2);
		Chart.AddItemData("Vans",40.0f,3);
		Chart.AddItemData("Bikes",70.0f,1);
		Chart.AddItemData("Bikes",75.0f,2);
		Chart.AddItemData("Bikes",80.0f,3);
		Chart.AddItemData("Bicycles",25.0f,1);
		Chart.AddItemData("Bicycles",23.0f,2);
		Chart.AddItemData("Bicycles",26.0f,3);
		Chart.AddItemData("Buses",5.0f,1);
		Chart.AddItemData("Buses",5.0f,2);
		Chart.AddItemData("Buses",5.0f,3);
		Chart.AddItemData("Trucks",25.0f,1);
		Chart.AddItemData("Trucks",27.0f,2);
		Chart.AddItemData("Trucks",26.0f,3);

			InvalidateRect(hwnd,NULL,FALSE);
			return 0;
		}

	case WM_SIZE:
		{
			InvalidateRect(hwnd,NULL,FALSE);
			return 0;
		}

	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hwnd,&ps);

			// Draw the Chart onto the screen dc
			Chart.DrawBar(hdc,30,30,300,300,RGB(0,0,0));


			EndPaint(hwnd,&ps);

			return 0;
		}


	case WM_DESTROY:
		PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
		break;
	default:                      /* for messages that we don't deal with */
		return DefWindowProc (hwnd, message, wParam, lParam);
	}

	return 0;
}






In the above program we set up three groups 2003 2005 and 2007 these groups are years.

we then add the individual item data these are concurrent ie the three bits of groupdata for that item must run after each other.

and that is it mainly in the next part we discuss how to set up Line Graphs.

See you next time.

Snoopy.

This post has been edited by baavgai: 17 February 2013 - 12:54 PM


Is This A Good Question/Topic? 0
  • +

Page 1 of 1