www.gusucode.com > 一个VC++ GUI测试程序-源码程序 > 一个VC++ GUI测试程序-源码程序/code/PieChartCtrl.cpp
//Download by http://www.NewXing.com // PieChartCtrl.cpp : implementation file // // Written by Yuheng Zhao (yuheng@ministars.com) // Copyright (c) 1998. // // This code may be used in compiled form in any way you desire. This // file may be redistributed unmodified by any means PROVIDING it is // not sold for profit without the authors written consent, and // providing that this notice and the authors name is included. If // the source code in this file is used in any commercial application // then a simple email would be nice. // // This file is provided "as is" with no expressed or implied warranty. // The author accepts no liability if it causes any damage whatsoever. // It's free - so you get what you pay for. #include "stdafx.h" #include "PieChartCtrl.h" #include <math.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif const double pi = 3.1415926535; ///////////////////////////////////////////////////////////////////////////// // CPieChartCtrl CPieChartCtrl::CPieChartCtrl() { CPieChartCtrl::RegisterWndClass(AfxGetInstanceHandle()); m_nStartAngle = 0; m_colorLine = RGB(0,0,0); m_colorDefault = RGB(0,0,255); m_rectChart.SetRect(0,0,0,0); m_bCaptured = FALSE; m_strTitle = _T(""); m_fontTitle.CreateFont(15, 0,0,0,FW_NORMAL, 0,0,0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial"); m_fontInfo.CreateFont(13, 0,0,0,FW_NORMAL, 0,0,0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial"); } CPieChartCtrl::~CPieChartCtrl() { Reset(); } BEGIN_MESSAGE_MAP(CPieChartCtrl, CWnd) //{{AFX_MSG_MAP(CPieChartCtrl) ON_WM_PAINT() ON_WM_LBUTTONUP() ON_WM_LBUTTONDOWN() ON_WM_MOUSEMOVE() ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CPieChartCtrl message handlers BOOL CPieChartCtrl::RegisterWndClass(HINSTANCE hInstance) { WNDCLASS wc; wc.lpszClassName = "PIE_CHART_CTRL"; // matches class name in client wc.hInstance = hInstance; wc.lpfnWndProc = ::DefWindowProc; wc.hCursor = ::LoadCursor(NULL, IDC_CROSS); wc.hIcon = 0; wc.lpszMenuName = NULL; wc.hbrBackground = (HBRUSH) ::GetStockObject(LTGRAY_BRUSH); wc.style = CS_GLOBALCLASS; // To be modified wc.cbClsExtra = 0; wc.cbWndExtra = 0; return (::RegisterClass(&wc) != 0); } void CPieChartCtrl::OnPaint() { if (m_rectChart.IsRectEmpty()) // First Time RecalcRect(); CPaintDC dc(this); // device context for painting CRect clientRect; GetClientRect(&clientRect); CBitmap *pOldMemDCBitmap = NULL; CDC memDC; CBitmap bitmap; memDC.CreateCompatibleDC(&dc); bitmap.CreateCompatibleBitmap( &dc, clientRect.Width(), clientRect.Height() ); CBitmap *pOldmemDCBitmap = (CBitmap*)memDC.SelectObject(&bitmap); memDC.FillSolidRect(clientRect, GetSysColor(COLOR_3DFACE)); CPen pen; pen.CreatePen(PS_SOLID, 1, m_colorLine); CPen* pOldPen = (CPen*)memDC.SelectStockObject(NULL_PEN); CBrush brush; brush.CreateSolidBrush(m_colorDefault); CBrush* pOldBrush = memDC.SelectObject(&brush); memDC.Ellipse(m_rectChart); int nCount = m_chartPieces.GetSize(); CPieChartPiece* pItem; CPoint pt1, pt2; int nCurrectAngle = m_nStartAngle; int nInfo=0; CountPoint(nCurrectAngle, pt1); for (int i=0; i<nCount; i++) { pItem = m_chartPieces.GetAt(i); nCurrectAngle += pItem->m_nAngle; CountPoint(nCurrectAngle, pt2); memDC.SelectStockObject(NULL_PEN); memDC.SelectObject(&pItem->m_brushBack); if (pt2!=pt1) memDC.Pie(m_rectChart, pt2, pt1); //Draw line memDC.SelectObject(&pen); memDC.MoveTo(pt1); memDC.LineTo(m_rectChart.CenterPoint()); memDC.LineTo(pt2); //Draw info CFont* pOldFont = memDC.SelectObject(&m_fontInfo); memDC.SetBkMode(TRANSPARENT); if (!(pItem->m_strInfo).IsEmpty()) { CSize sz = memDC.GetTextExtent(pItem->m_strInfo); CRect rcColor(clientRect); rcColor.left = rcColor.right - sz.cy; rcColor.bottom = rcColor.top + sz.cy; rcColor.OffsetRect(0, nInfo*rcColor.Height());//+m_nTitleHeight); memDC.FillSolidRect(rcColor, pItem->m_colorBack); // i must be less than MAX_COLOR memDC.DrawEdge(rcColor, EDGE_SUNKEN, BF_RECT); memDC.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); rcColor.right = rcColor.left - 3; rcColor.left = clientRect.left; memDC.DrawText(pItem->m_strInfo, rcColor, DT_RIGHT|DT_VCENTER); nInfo++; } // Draw percent if (pItem->m_nAngle>25) { int n = nCurrectAngle - (pItem->m_nAngle)/2; CPoint p; CountPoint(n, p, TRUE); CString str; str.Format("%.0f%%", (double)(pItem->m_nAngle)*100.0/360.0); CSize sz = memDC.GetTextExtent(str); memDC.SetTextColor(pItem->m_colorText); memDC.TextOut(p.x-sz.cx/2, p.y-sz.cy/2, str); } memDC.SelectObject(pOldFont); pt1 = pt2; } // Draw Line for the out circle memDC.SelectObject(&pen); memDC.SelectStockObject(NULL_BRUSH); memDC.Ellipse(m_rectChart); //Draw Title if (!m_strTitle.IsEmpty()) { CFont* pOldFont = memDC.SelectObject(&m_fontTitle); memDC.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); memDC.SetBkMode(TRANSPARENT); memDC.TextOut(1, 1, m_strTitle); memDC.SelectObject(pOldFont); } dc.BitBlt( 0, 0, clientRect.Width(), clientRect.Height(), &memDC, 0, 0, SRCCOPY ); memDC.SelectObject(pOldPen); memDC.SelectObject(&pOldBrush); memDC.SelectObject(pOldmemDCBitmap); } void CPieChartCtrl::OnLButtonUp(UINT, CPoint) { if (m_bCaptured) { ::ReleaseCapture(); m_bCaptured = FALSE; } } void CPieChartCtrl::OnLButtonDown(UINT, CPoint point) { SetCapture(); m_bCaptured = TRUE; m_ptOldPt = point; } void CPieChartCtrl::OnMouseMove(UINT, CPoint point) { if (m_bCaptured) { int nOffX = point.x - m_ptOldPt.x; m_nStartAngle += nOffX; InvalidateRect(m_rectChart, FALSE); m_ptOldPt = point; } } void CPieChartCtrl::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); RecalcRect(); } void CPieChartCtrl::RecalcRect() { CRect rect; GetClientRect(&rect); if (!m_strTitle.IsEmpty()) { CClientDC dc(this); CFont* pOldFont = dc.SelectObject(&m_fontTitle); CSize sz = dc.GetTextExtent(m_strTitle); m_nTitleHeight = sz.cy; rect.top += sz.cy*2;// Leave lines. dc.SelectObject(pOldFont); } int nSize = (rect.Width()>rect.Height())?rect.Height():rect.Width(); m_rectChart = CRect(CPoint(rect.left + (rect.Width()-nSize)/2, rect.top + (rect.Height()-nSize)), CSize(nSize, nSize)); } BOOL CPieChartCtrl::AddPiece(COLORREF colorBack, COLORREF colorText, int nAngle, const CString& str) { CPieChartPiece* pItem = new CPieChartPiece; pItem -> m_colorBack = colorBack; pItem -> m_colorText = colorText; pItem -> m_brushBack.CreateSolidBrush(colorBack); pItem -> m_nAngle = nAngle; pItem -> m_strInfo = str; try { m_chartPieces.Add(pItem); InvalidateRect(NULL, FALSE); return TRUE; } catch (CMemoryException* e) { if (pItem !=NULL) delete pItem; e->Delete(); return FALSE; } } // bPercent is TRUE when counting the position for the percent info void CPieChartCtrl::CountPoint(int nAngle, CPoint & pt, BOOL bPercent) { while (nAngle <0) nAngle += 360; while (nAngle>359) nAngle -= 360; double dAngle = ((double)nAngle)*pi/(double)180; double r; r = ((double)m_rectChart.Height())/2.0; if (bPercent) r = r*3.0/5.0; double dOffX = (r*sin(dAngle)); double dOffY = 0.0 - (r*cos(dAngle)); double dX = ((double)(m_rectChart.right+m_rectChart.left))/2.0; double dY = ((double)(m_rectChart.top+m_rectChart.bottom))/2.0; pt.x = (int)(dX + dOffX); pt.y = (int)(dY + dOffY); } void CPieChartCtrl::Reset() { int nCount = m_chartPieces.GetSize(); for (int i = 0; i < nCount; i++) delete m_chartPieces.GetAt(i); m_chartPieces.RemoveAll(); } void CPieChartCtrl::GetItemColor(int i, COLORREF& color) { int nCount = m_chartPieces.GetSize(); if (i>=nCount) i=nCount-1; color = (m_chartPieces.GetAt(i))->m_colorBack; } void CPieChartCtrl::SetTitle(const CString & str) { m_strTitle = str; RecalcRect(); InvalidateRect(NULL, FALSE); }