📄 barchart.cpp
字号:
void CBarChart::CChartBar::ShowBarText(int nType, BOOL bShow)
{
m_bShowBarText = bShow;
m_nBarTextType = nType;
}
void CBarChart::CChartBar::DisplayToolTip(CPoint& point, CRect& rcBound,
CRect& rcMemPic, BOOL bScale, CString& szTip)
{
if (bScale)
{
m_dAlpha = (double)rcBound.Width()/ (double)(m_sBarPicSize.cx+m_rMargin*2);
}
else
{
m_dAlpha = (double)rcMemPic.Width()/ (double)(m_sBarPicSize.cx+m_rMargin*2);
}
m_dIndex = (int) ( (double)(point.x - m_rMargin*m_dAlpha) /
(double)((m_nBarWidth*m_dAlpha) + (m_nBarGap*m_dAlpha)) );
if (m_dIndex<0.0 || (int)m_dIndex>=m_chartData.GetCount())
{
szTip = "";
}
else
{
szTip.Format("%s\n%0.04f\n%0.02f%%\n",
m_chartData.GetLabel((int)m_dIndex),m_chartData.GetValue((int)m_dIndex),
(m_chartData.GetValue((int)m_dIndex)*100)/m_chartData.GetMaxValue());
}
}
BOOL CBarChart::CChartBar::IsLabelVisible()
{
return m_bShowLabel;
}
///////////////////////////////////////////////////////////////////////
// CChartGCalc Class
//
//
// A set of handy GDI functions for manipulating
// pixel colors, etc.
//
///////////////////////////////////////////////////////////////////////
UINT CChartGCalc::GABS (const int& nmbr)
{
return (nmbr>0)?nmbr:-nmbr;
}
COLORREF CChartGCalc::DifColor(COLORREF color, UINT nDist)
{
return RGB(
GABS(GetRValue(color)-nDist),
GABS(GetGValue(color)-nDist),
GABS(GetBValue(color)-nDist)
);
}
COLORREF CChartGCalc::OrColor(COLORREF colFore, COLORREF colBK, UINT nForePercent)
{
return RGB (
( GetRValue(colBK)*100 + ( nForePercent*(GetRValue(colFore)-GetRValue(colBK)) ) ) /100,
( GetGValue(colBK)*100 + ( nForePercent*(GetGValue(colFore)-GetGValue(colBK)) ) ) /100,
( GetBValue(colBK)*100 + ( nForePercent*(GetBValue(colFore)-GetBValue(colBK)) ) ) /100 );
}
// Refer to the following article in 'CodeProject.com' By 'Roger Allen'
// 'Printing tips and tricks from the trenches'
// And goto topic: 'Use DIB's instead of DDB's'
// DDBToDIB - Creates a DIB from a DDB
// bitmap - Device dependent bitmap
// dwCompression - Type of compression - see BITMAPINFOHEADER
// pPal - Logical palette
HANDLE CChartGCalc::DDBToDIB( CBitmap* bitmap, DWORD dwCompression, CPalette* pPal )
{
BITMAP bm;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen;
HANDLE hDIB;
HANDLE handle;
HDC hDC;
HPALETTE hPal;
ASSERT( bitmap->GetSafeHandle() );
// The function has no arg for bitfields
if( dwCompression == BI_BITFIELDS )
return NULL;
// If a palette has not been supplied use default palette
hPal = (HPALETTE) pPal->GetSafeHandle();
if (hPal==NULL)
hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
// Get bitmap information
bitmap->GetObject(sizeof(bm),(LPSTR)&bm);
// Initialize the bitmapinfoheader
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = (unsigned short)(bm.bmPlanes * bm.bmBitsPixel) ;
bi.biCompression = dwCompression;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
// Compute the size of the infoheader and the color table
int nColors = 0;
if(bi.biBitCount <= 8)
{
nColors = (1 << bi.biBitCount);
}
dwLen = bi.biSize + nColors * sizeof(RGBQUAD);
// We need a device context to get the DIB from
hDC = ::GetDC(NULL);
hPal = SelectPalette(hDC,hPal,FALSE);
RealizePalette(hDC);
// Allocate enough memory to hold bitmapinfoheader and color table
hDIB = GlobalAlloc(GMEM_FIXED,dwLen);
if (!hDIB){
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
*lpbi = bi;
// Call GetDIBits with a NULL lpBits param, so the device driver
// will calculate the biSizeImage field
GetDIBits(hDC, (HBITMAP)bitmap->GetSafeHandle(), 0L, (DWORD)bi.biHeight,
(LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);
bi = *lpbi;
// If the driver did not fill in the biSizeImage field, then compute it
// Each scan line of the image is aligned on a DWORD (32bit) boundary
if (bi.biSizeImage == 0){
bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
* bi.biHeight;
// If a compression scheme is used the result may infact be larger
// Increase the size to account for this.
if (dwCompression != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}
// Realloc the buffer so that it can hold all the bits
dwLen += bi.biSizeImage;
handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE) ;
if (handle != NULL)
hDIB = handle;
else
{
GlobalFree(hDIB);
// Reselect the original palette
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}
// Get the bitmap bits
lpbi = (LPBITMAPINFOHEADER)hDIB;
// FINALLY get the DIB
BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap->GetSafeHandle(),
0L, // Start scan line
(DWORD)bi.biHeight, // # of scan lines
(LPBYTE)lpbi // address for bitmap bits
+ (bi.biSize + nColors * sizeof(RGBQUAD)),
(LPBITMAPINFO)lpbi, // address of bitmapinfo
(DWORD)DIB_RGB_COLORS); // Use RGB for color table
if( !bGotBits )
{
GlobalFree(hDIB);
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return hDIB;
}
///////////////////////////////////////////////////////////////////////
// CChartData Class
//
// Holds data of a chart and let the chart to do
// reqauered operations on it
//
///////////////////////////////////////////////////////////////////////
CBarChart::CChartData::CChartData()
{
m_udMax = 0;
}
void CBarChart::CChartData::CalculateMaximum()
{
for (int i=0;i<m_arr.GetSize();i++)
{
if (m_udMax<((data*)m_arr.GetAt(i))->m_udValue)
{
m_udMax = ((data*)m_arr.GetAt(i))->m_udValue;
}
}
}
void CBarChart::CChartData::RemoveAll()
{
data* pData;
for (int i=0;i<m_arr.GetSize();i++ ){
if ( (pData=(data*)m_arr.GetAt(i))!=NULL ) {
delete pData;
}
}
m_arr.RemoveAll();
m_udMax = 0;
}
void CBarChart::CChartData::RemoveAt(int nIndex)
{
if (m_arr.GetSize()==0)
return;
if (nIndex>=m_arr.GetSize() || nIndex<0)
{
return;
}
delete (data*) m_arr.GetAt(nIndex);
m_arr.RemoveAt(nIndex);
CalculateMaximum();
}
int CBarChart::CChartData::GetCount()
{
return m_arr.GetSize();
}
void CBarChart::CChartData::Add (CString& szLabel, double udValue, COLORREF color)
{
data *pData;
pData = new data;
pData->m_szLabel = szLabel;
pData->m_udValue = udValue;
pData->m_color = color;
m_arr.Add((CObject*)pData);
if (m_udMax<udValue)
{
m_udMax = udValue;
}
}
double CBarChart::CChartData::GetMaxValue()
{
if (m_udMax!=0)
{
return m_udMax;
}
else
{
// Eliminate probability of division by zero
return 1;
}
}
double CBarChart::CChartData::GetValue(int nIndex)
{
if (nIndex<0 || nIndex>=m_arr.GetSize())
{
return -1;
}
return ((data*)m_arr.GetAt(nIndex))->m_udValue;
}
CString CBarChart::CChartData::GetLabel(int nIndex)
{
if (nIndex<0 || nIndex>=m_arr.GetSize())
{
return "";
}
return ((data*)m_arr.GetAt(nIndex))->m_szLabel;
}
COLORREF CBarChart::CChartData::GetColor(int nIndex)
{
if (nIndex<0 || nIndex>=m_arr.GetSize())
{
return RGB(0, 0, 0);
}
return ((data*)m_arr.GetAt(nIndex))->m_color;
}
///////////////////////////////////////////////////////////////////////
// CChartPrinter Class
//
// No need to description(!) This class should print the
// Chart using print dialog.
//
///////////////////////////////////////////////////////////////////////
// Many of the following code, had been stolen shamelessly from ChrisMaunder's Best work: MFCGrid
// Find it in 'www.codeproject.com'
void CBarChart::CChartPrinter::Print(CDC* pDC, CDC *pMemDC, CBitmap* pBmp,
CString szTitle, CRect& rcMemPic, BOOL bFit,
BOOL bCompatible)
{
CDC dc;
CPrintDialog printDlg(FALSE);
if (printDlg.DoModal() != IDOK) // Get printer settings from user
return;
dc.Attach(printDlg.GetPrinterDC()); // attach a printer DC
m_rcMemPic = rcMemPic;
m_pMemDC = pMemDC;
m_pBmpMem = pBmp;
m_bScale = bFit;
DOCINFO di; // Initialise print doc details
memset(&di, 0, sizeof (DOCINFO));
di.cbSize = sizeof (DOCINFO);
di.lpszDocName = szTitle;
BOOL bPrintingOK = dc.StartDoc(&di); // Begin a new print job
CPrintInfo info;
info.m_rectDraw.SetRect(0,0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
dc.StartPage(); // begin new page
if (bCompatible)
{
OnPrintCompatible(&dc, &info);
}
else
{
OnPrint(&dc, &info);
}
bPrintingOK = (dc.EndPage() > 0); // end page
if (bPrintingOK)
dc.EndDoc(); // end a print job
else
dc.AbortDoc(); // abort job.
dc.Detach(); // detach the printer DC
}
void CBarChart::CChartPrinter::OnPrint (CDC *pDC, CPrintInfo* pInfo)
{
// Do some calculations
pDC->SetMapMode(MM_ANISOTROPIC);
pInfo->m_nCurPage = 1;
pInfo->SetMaxPage(1);
// UNDONE : SET TRUE MAPPING MODE, AND CALCULATIONS, IN CASE OF NON-SCALED CHART PRINTING
// if (m_bScale)
// {
pDC->StretchBlt(pInfo->m_rectDraw.left,
pInfo->m_rectDraw.top, pInfo->m_rectDraw.Width(), pInfo->m_rectDraw.Height(),
m_pMemDC, 0, 0, m_rcMemPic.Width(), m_rcMemPic.Height(),
SRCCOPY);
// }
// else
// {
// pDC->BitBlt(pInfo->m_rectDraw.left,
// pInfo->m_rectDraw.top, pInfo->m_rectDraw.Width(), pInfo->m_rectDraw.Height(),
// m_pMemDC, 0, 0, SRCCOPY);
// }
}
// Refered to the following article in 'CodeProject.com' By 'Roger Allen'
// 'Printing tips and tricks from the trenches'
// And in topic: 'Use DIB's instead of DDB's'
// Print function might not work is a DDB blotting is done
void CBarChart::CChartPrinter::OnPrintCompatible (CDC *pDC, CPrintInfo* pInfo)
{
// Do some calculations
pDC->SetMapMode(MM_ANISOTROPIC);
pInfo->m_nCurPage = 1;
pInfo->SetMaxPage(1);
CPalette pal;
UINT nSize = sizeof(LOGPALETTE) + ( sizeof(PALETTEENTRY) * 256 );
LOGPALETTE* pLP = (LOGPALETTE*)new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = (unsigned short)GetSystemPaletteEntries( m_pMemDC->GetSafeHdc(), 0, 255,
pLP->palPalEntry );
// Create the palette
pal.CreatePalette( pLP );
// Free memory
delete[] pLP;
// Convert the bitmap to a DIB
HANDLE hDib = DDBToDIB(m_pBmpMem, BI_RGB, &pal );
BITMAPINFOHEADER *pBMI ;
pBMI = (BITMAPINFOHEADER*)GlobalLock(hDib) ;
int nColors = 0;
if (pBMI->biBitCount <= 8)
{
nColors = (1 << pBMI->biBitCount);
}
// print the correct image
::StretchDIBits(pDC->m_hDC,
pInfo->m_rectDraw.left,
pInfo->m_rectDraw.top,
pInfo->m_rectDraw.Width(),
pInfo->m_rectDraw.Height(),
0,
0,
pBMI->biWidth,
pBMI->biHeight,
(LPBYTE)pBMI + (pBMI->biSize + nColors * sizeof(RGBQUAD)),
(BITMAPINFO*)pBMI,
DIB_RGB_COLORS,
SRCCOPY);
// free resources
GlobalUnlock(hDib) ;
GlobalFree(hDib) ;
}
///////////////////////////////////////////////////////////////////////
// CChartTip Class
//
//
// Adds tooltip capabilities for bar chart.
// Tooltip should show: value, Label and percentage
//
///////////////////////////////////////////////////////////////////////
CChartTip::CChartTip()
{
if ( m_lpszClass == NULL ) m_lpszClass = AfxRegisterWndClass( CS_SAVEBITS );
if ( m_lpszClass == NULL ) m_lpszClass = AfxRegisterWndClass( CS_SAVEBITS );
}
CChartTip::~CChartTip()
{
if (m_brShadow.GetSafeHandle())
{
m_brShadow.DeleteObject();
}
if (m_brFrame.GetSafeHandle())
{
m_brFrame.DeleteObject();
}
if (m_brBK.GetSafeHandle())
{
m_brBK.DeleteObject();
}
if (m_fontBold.GetSafeHandle())
{
m_fontBold.DeleteObject();
}
if (m_fontNorm.GetSafeHandle())
{
m_fontNorm.DeleteObject();
}
// Shall not do delete m_rgnTip
// System will delete this rgn whenever doesnot need it any more
if (m_rgnCopy.GetSafeHandle())
{
m_rgnCopy.DeleteObject();
}
if (m_bTimer)
{
if (m_hWnd != NULL )
{
m_bTimer = FALSE;
KillTimer(TIP_DELAY_TIMER);
}
}
if (m_hWnd)
{
if (IsWindowVisible())
{
HideWindow();
}
}
if ( m_hWnd != NULL ) DestroyWindow();
}
BEGIN_MESSAGE_MAP(CChartTip, CWnd)
//{{AFX_MSG_MAP(CChartTip)
ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CChartTip message handlers
LPCTSTR CChartTip::m_lpszClass = NULL;
BOOL CChartTip::Create(CWnd *pParentWnd, BOOL *pbEnable, CString* lpszTitle, int nDelay)
{
m_rcClient = CRect(0, 0, 0, 0);
DWORD dwStyleEx = WS_EX_TOPMOST;
if ( ! CWnd::CreateEx( dwStyleEx, m_lpszClass, NULL, WS_POPUP,
m_rcClient, pParentWnd, 0, NULL ) ) return FALSE;
SetOwner( pParentWnd );
m_pbEnable = pbEnable;
m_lpszTitle = lpszTitle;
m_nDelay = nDelay;
m_bTimer = FALSE;
m_rcClient = CRect(0, 0, 120 , 100);
// create a brush
m_brFrame.CreateSolidBrush(TIP_FRAME_COLOR);
m_brShadow.CreateSolidBrush(TIP_SHADOW_COLOR);
m_brBK.CreateSolidBrush(TIP_BK_COLOR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -