Click here to Skip to main content
15,894,646 members
Articles / Desktop Programming / MFC

Bar Graph Control

Rate me:
Please Sign up or sign in to vote.
3.63/5 (13 votes)
5 Feb 2007CPOL2 min read 72.9K   3.4K   45  
A useful bar graph control, derived from CStatic.
// GraphCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "GraphTest.h"
#include "GraphCtrl.h"
#include ".\graphctrl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CGraphCtrl

CGraphCtrl::CGraphCtrl()
{
	offsetx = 50;
	offsety = 40;
	strcpy(sUnit, "cm");
	scale = 5;
	iStart = 0;
	iEnd = 100;
	BGC = RGB(224,231,240);
	AxisC = RGB(0,0,0);
	TextC = RGB(0,0,0);
}

CGraphCtrl::~CGraphCtrl()
{

}

BEGIN_MESSAGE_MAP(CGraphCtrl, CStatic)
	//{{AFX_MSG_MAP(CGraphCtrl)
	ON_WM_DRAWITEM()
	ON_WM_PAINT()
	ON_WM_TIMER()
	ON_WM_CREATE()
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGraphCtrl message handlers

BOOL CGraphCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	return CStatic::OnNotify(wParam, lParam, pResult);
}

BOOL CGraphCtrl::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
	// TODO: Add your specialized code here and/or call the base class

	return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}

LRESULT CGraphCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	return CStatic::WindowProc(message, wParam, lParam);
}

void CGraphCtrl::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	// TODO: Add your message handler code here and/or call default
	
	CStatic::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

void CGraphCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here
	DrawGraph();

	// Do not call CStatic::OnPaint() for painting messages
}

void CGraphCtrl::OnTimer(UINT nIDEvent) 
{
	
	CStatic::OnTimer(nIDEvent);
}

int CGraphCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CStatic::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here

	return 0;
}

void CGraphCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LPNMCUSTOMDRAW lpcd = (LPNMCUSTOMDRAW)pNMHDR;
	CDC *pDC = CDC::FromHandle(lpcd->hdc);
	switch(lpcd->dwDrawStage)
	{
		case CDDS_PREPAINT:
			*pResult = CDRF_NOTIFYITEMDRAW;
			break;
			//return;
		case CDDS_ITEMPREPAINT:
			if (lpcd->dwItemSpec == TBCD_THUMB)
			{
				*pResult = CDRF_DODEFAULT;
				break;
			}
			break;
	}
}

int CGraphCtrl::AddBar(int iVal, COLORREF bClr, const char* sLabel)
{
	BAR_DATA cBar;
	cBar.iVal = iVal;
	cBar.barClr = bClr;
	strncpy(cBar.sLabel, sLabel, 15);

	POSITION pos = listBars.AddTail(cBar);

	return listBars.GetCount();
}

int CGraphCtrl::InsertBar(int index,int iVal, COLORREF bClr, const char* sLabel)
{
	if(index <0 || index >= listBars.GetCount())
		return -1;

	BAR_DATA cBar;
	cBar.iVal = iVal;
	cBar.barClr = bClr;
	strncpy(cBar.sLabel, sLabel, 15);

	listBars.InsertAfter(listBars.FindIndex(index), cBar);

	return listBars.GetCount();
}

int CGraphCtrl::DeleteBar(int index)
{
	if(index <0 || index >= listBars.GetCount())
		return -1;
	listBars.RemoveAt(listBars.FindIndex(index));

	return listBars.GetCount();
}

int CGraphCtrl::GetNumberOfBars()
{
	return listBars.GetCount();
}

void CGraphCtrl::SetBarValue(int index, int val, BOOL bDraw)
{
	if(index <0 || index >= listBars.GetCount())
		return;

	BAR_DATA cBar = listBars.GetAt(listBars.FindIndex(index));
	cBar.iVal = val;
	listBars.SetAt(listBars.FindIndex(index), cBar);

	if(bDraw)
		DrawGraph();
}

void CGraphCtrl::SetBarColor(int index, COLORREF Clr, BOOL bDraw)
{
	if(index <0 || index >= listBars.GetCount())
		return;

	BAR_DATA cBar = listBars.GetAt(listBars.FindIndex(index));
	cBar.barClr = Clr;
	listBars.SetAt(listBars.FindIndex(index), cBar);

	if(bDraw)
		DrawGraph();
}

int CGraphCtrl::GetBarValue(int index)
{
	if(index <0 || index >= listBars.GetCount())
		return -1;

	BAR_DATA cBar = listBars.GetAt(listBars.FindIndex(index));

	return cBar.iVal;
}

COLORREF CGraphCtrl::GetBarColor(int index)
{
	if(index <0 || index >= listBars.GetCount())
		return -1;

	BAR_DATA cBar = listBars.GetAt(listBars.FindIndex(index));

	return cBar.barClr;
}

void CGraphCtrl::SetUnit(CString pUnit)
{
	strcpy(sUnit, pUnit);

	DrawGraph();
}

void CGraphCtrl::SetScale(int iScl)
{
	if(iScl <= 0)
		return;

	scale = iScl;

	DrawGraph();
}

int CGraphCtrl::GetScale()
{
	return scale;
}

COLORREF CGraphCtrl::GetBGColor()
{
	return BGC;
}

void CGraphCtrl::SetBGColor(COLORREF pBG)
{
	BGC = pBG;

	DrawGraph();
}

void CGraphCtrl::SetAxisColor(COLORREF pAxC)
{
	AxisC = pAxC;
	DrawGraph();
}

COLORREF CGraphCtrl::GetAxisColor()
{
	return AxisC;
}

void CGraphCtrl::SetTextColor(COLORREF pTxC)
{
	TextC = pTxC;
	DrawGraph();
}

COLORREF CGraphCtrl::GetTextColor()
{
	return TextC;
}

BOOL CGraphCtrl::PreCreateWindow(CREATESTRUCT& cs) 
{
	// TODO: Add your specialized code here and/or call the base class

	return CStatic::PreCreateWindow(cs);
}

int CGraphCtrl::DrawGraph(void)
{
	CDC MemDC;
    CBitmap MemBitmap;
	LOGFONT lf;
	CString str;
	CFont newFont, newFont1;

	CRect rc;
	GetClientRect (rc);
	int Width = rc.Width();
	int Height= rc.Height();

	CDC* pDC = GetDC();
    MemDC.CreateCompatibleDC(pDC);
	MemBitmap.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());
	CBitmap *pOldBitmap = MemDC.SelectObject(&MemBitmap);

	CFont* pFont = MemDC.GetCurrentFont();
	pFont->GetLogFont(&lf);
	lf.lfHeight = (-1)*MulDiv(9, MemDC.GetDeviceCaps(LOGPIXELSY), 72);

	memset(&lf, 0, sizeof(lf));
	lstrcpy(lf.lfFaceName, "Arial"); 
	lf.lfHeight = (-1)*MulDiv(9, MemDC.GetDeviceCaps(LOGPIXELSY), 72);
	lf.lfWeight = 700;
	newFont.CreateFontIndirect(&lf);
	lf.lfEscapement = 900;
	newFont1.CreateFontIndirect(&lf);

	MemDC.SelectObject(&newFont1);

	int bx=0, by=0;
	MemDC.FillSolidRect(0,0,Width,Height,BGC);

	MemDC.FillSolidRect(offsetx-2, 0, 2, Height-(offsety-2), AxisC);
	MemDC.FillSolidRect(offsetx, Height-offsety, Width-offsetx, 2, AxisC);

	MemDC.SetBkMode(TRANSPARENT);
	MemDC.SetTextColor(TextC);

	int iActHt = (Height-offsety);
	int iDiv = (iActHt-5)/((iEnd-iStart)/scale);

	str.Format("%s =>", sUnit);
	MemDC.ExtTextOut(0, iActHt-20, 0, NULL, str, NULL );

	MemDC.SelectObject(&newFont);

	int iIdx = 0;
	for(int i=offsety; i<=iActHt+offsety+5; i+=(iDiv/2))
	{
		if(iIdx%2)
		{
			MemDC.FillSolidRect(offsetx-6, Height-i, 4, 1, AxisC);
		}
		else
		{
			MemDC.FillSolidRect(offsetx-10, Height-i, 8, 1, AxisC);

			str.Format("%d", iStart+(iIdx/2)*scale);
			MemDC.ExtTextOut(17, Height-i - 8, 0, NULL, str, NULL );
		}
		iIdx++;
	}

	int NumOfBars = listBars.GetCount();
	for(i=0;i<NumOfBars;i++)
	{
		BAR_DATA cBar = listBars.GetAt(listBars.FindIndex(i));
		int pixVal = ((float)(cBar.iVal-iStart)/(float)scale) * (float)iDiv;
		bx = ((Width-offsetx)/NumOfBars)*i+offsetx;
		if(pixVal>0)
		{
			MemDC.FillSolidRect(bx, iActHt-pixVal,(Width-offsety)/NumOfBars,pixVal,cBar.barClr);
			MemDC.Draw3dRect(bx, iActHt-pixVal,(Width-offsety)/NumOfBars,pixVal,RGB(255,255,255),cBar.barClr);
		}

		str = cBar.sLabel;
		MemDC.ExtTextOut(bx, iActHt+2, 0, NULL, str, NULL );
	}

	//Draw
	pDC->BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &MemDC, 0, 0, SRCCOPY);
	MemDC.SelectObject(pOldBitmap);

	return 0;
}

int CGraphCtrl::SetDisplayRange(int iRangeStart, int iRangeEnd)
{
	if(iRangeStart>=0 && iRangeEnd>=0)
	{
		iStart = iRangeStart;
		iEnd = iRangeEnd;
	}

	DrawGraph();
	return 1;
}

void CGraphCtrl::GetDisplayRange(int& iRangeStart, int& iRangeEnd)
{
	iRangeStart = iStart;
	iRangeEnd = iEnd;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Team Leader
India India
Mr. Shaibujan has got 9+ yrs of programming experience in C/C++, on various domains like Cryptography, Biometric Security, Network Security, Pattern Recognition, Image Processing, MPEG2, MPEG4, H.264, AAC etc.

Comments and Discussions