📄 barchart.cpp
字号:
cDB.MoveNext();
}
Refresh();
return TRUE;
}
// This function tryes to read chart data from an Stored Procedure or Query
BOOL CBarChart::ReadFromDatabase(CString szDSN, CString szSPName, CString szParameterList,
COLORREF colorBars, CString szUsername, CString szPass)
{
CChartDatabase cSP;
if (!cSP.OpenProc(szDSN, szSPName, szParameterList, szUsername, szPass))
{
m_szLastErr = cSP.GetLastErrorMessage();
return FALSE;
};
CString szLabel;
double dVal;
while (!cSP.IsEOF())
{
cSP.GetRow(szLabel, dVal);
if (colorBars == RGB(0, 0, 0))
{
AddBar(dVal, szLabel, RGB(rand()%255, rand()%255, rand()%255));
}
else
{
AddBar(dVal, szLabel, colorBars);
}
cSP.MoveNext();
}
Refresh();
return TRUE;
}
CString CBarChart::GetLastDatabaseErrMessage()
{
return m_szLastErr;
}
CString CBarChart::GetLastErrorMessage()
{
return GetLastDatabaseErrMessage();
}
BOOL CBarChart::SaveToFile(CString szPath)
{
// to return results
BOOL bRes = TRUE;
// If chart is not ready
if ( m_dcMem.GetSafeHdc() == NULL )
{
return FALSE;
}
// If no path specified, ask for a path
if (szPath=="")
{
if ( !PromptForFile(szPath, _T("Bitmap file"), _T("*.Bmp")) )
{
m_szLastErr = "Canceled by user";
return FALSE;
}
}
BITMAPINFOHEADER *pBMI ;
BITMAPFILEHEADER hdr;
DWORD dwTotal; // total count of bytes
DWORD cb; // incremental count of bytes
CPalette pal;
DWORD dwWritten = 0;
LPBYTE hp;
// Prepare for converting DDB to DIB
UINT nSize = sizeof(LOGPALETTE) + ( sizeof(PALETTEENTRY) * 256 );
LOGPALETTE* pLP = (LOGPALETTE*)new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = (unsigned short)GetSystemPaletteEntries(
m_dcMem.GetSafeHdc(), 0, 255,
pLP->palPalEntry );
// Create the palette
pal.CreatePalette( pLP );
// Free memory
delete[] pLP;
// Do convert DDB to DIB
HANDLE hDib = DDBToDIB( m_pBmpBars, BI_RGB, &pal );
// Prepare Bitmap Info Header
pBMI = (BITMAPINFOHEADER*)GlobalLock(hDib) ;
int nColors = 0;
if (pBMI->biBitCount <= 8)
{
nColors = (1 << pBMI->biBitCount);
}
// Prepare FileHeader
hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
// Compute the size of the entire file.
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
pBMI->biSize + pBMI->biClrUsed
* sizeof(RGBQUAD) + pBMI->biSizeImage);
// Compute the offset to the array of color indices.
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
pBMI->biSize + pBMI->biClrUsed
* sizeof (RGBQUAD);
// Create the .BMP file.
HANDLE hf = CreateFile(szPath,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hf == INVALID_HANDLE_VALUE)
{
m_szLastErr = "Cannot create file";
bRes = FALSE;
goto CLEANUP;
}
// Copy the BITMAPFILEHEADER into the .BMP file.
if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
(LPDWORD) &dwWritten, NULL))
{
m_szLastErr = "Cannot write to file";
bRes = FALSE;
goto CLEANUP;
}
// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
if (!WriteFile(hf, (LPVOID) pBMI, sizeof(BITMAPINFOHEADER)
+ pBMI->biClrUsed * sizeof (RGBQUAD),
(LPDWORD) &dwWritten, ( NULL)) )
{
m_szLastErr = "Cannot write to file";
bRes = FALSE;
goto CLEANUP;
}
// Copy the array of color indices into the .BMP file.
dwTotal = cb = pBMI->biSizeImage;
hp = (LPBYTE)pBMI + (pBMI->biSize + nColors * sizeof(RGBQUAD));
if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwWritten,NULL))
{
m_szLastErr = "Cannot write to file";
bRes = FALSE;
goto CLEANUP;
}
CLEANUP:;
// free resources
GlobalUnlock(hDib) ;
GlobalFree(hDib) ;
// Close the .BMP file.
if ( hf != INVALID_HANDLE_VALUE )
{
if (!CloseHandle(hf))
{
m_szLastErr = "Cannot close file";
return FALSE;
}
}
return bRes;
}
BOOL CBarChart::PromptForFile(CString& szPath, CString szFilterName, CString szFilter)
{
CString szFltr;
szFltr.Format(_T("%s|%s||"), szFilterName, szFilter);
// If path did not set, ask for a path
CFileDialog fileSDlg(
FALSE, // Not an open file dialog
_T("bmp"), // This is to save bitmap files
NULL, // No default file name
OFN_ENABLESIZING |
//OFN_FORCESHOWHIDDEN |
OFN_LONGNAMES |
OFN_OVERWRITEPROMPT |
OFN_PATHMUSTEXIST,
szFltr);
if ( fileSDlg.DoModal() != IDOK )
{
return FALSE;
}
szPath = fileSDlg.GetPathName();
return TRUE;
}
void CBarChart::SetGridLines(int nHorLineCount, int nVerLineCount,
BOOL bFixedSize, int nFixedSize)
{
m_grid.SetLineCount(nVerLineCount, nHorLineCount, bFixedSize, nFixedSize);
}
///////////////////////////////////////////////////////////////////////
// CGDIGrid Class
//
// Draws a grid behind the chart.
// UNDONE: The grid class should act better. instead of
// drawing horizontal lines from top, it should start
// from the line under the bars. (Logical y = 0 axe)
//
///////////////////////////////////////////////////////////////////////
void CBarChart::CGDIGrid::Draw(CDC* pDC, CRect& rcBound)
{
if (m_penGrid.GetSafeHandle()) {
m_pPenOld= pDC->SelectObject(&m_penGrid);
// |||
int nGapSize = (m_nVLineCount==0?m_nFixedSize:
(rcBound.Width()-2*GRID_MARGIN_WIDTH)/m_nVLineCount);
if (nGapSize<=0)
{
nGapSize = 1;
}
for (i=rcBound.left+GRID_MARGIN_WIDTH ;i<rcBound.right-2*GRID_MARGIN_WIDTH;
i+=nGapSize)
{
pDC->MoveTo(i, GRID_MARGIN_WIDTH);
pDC->LineTo(i, rcBound.Height());
}
// ===
nGapSize = (m_nHLineCount==0?m_nFixedSize:
(rcBound.Height()-GRID_MARGIN_WIDTH)/m_nHLineCount);
if (nGapSize<=0)
{
nGapSize = 1;
}
for (i=rcBound.bottom ; i>=rcBound.top+GRID_MARGIN_WIDTH ;
i-=nGapSize)
{
pDC->MoveTo( GRID_MARGIN_WIDTH, i);
pDC->LineTo( rcBound.Width() - 2*GRID_MARGIN_WIDTH, i);
}
}
// Cleanup
pDC->SelectObject(m_pPenOld);
};
CBarChart::CGDIGrid::CGDIGrid()
{
m_nVLineCount = 0;
m_nHLineCount = 0;
m_nFixedSize = GRID_DEFAULT_SIZE;
m_pPenOld = NULL;
};
CBarChart::CGDIGrid::~CGDIGrid()
{
if (m_penGrid.GetSafeHandle())
{
m_penGrid.DeleteObject();
}
};
void CBarChart::CGDIGrid::SetLineCount(UINT nVLineCnt, UINT nHLineCnt, BOOL bFixedSize, UINT nFixedSize)
{
if (bFixedSize)
{
if (nFixedSize==0)
{
m_nFixedSize = GRID_DEFAULT_SIZE;
}
else
{
m_nFixedSize = nFixedSize;
}
m_nVLineCount = 0;
m_nHLineCount = 0;
}
else
{
if (nVLineCnt!=0) m_nVLineCount = nVLineCnt;
if (nHLineCnt!=0) m_nHLineCount = nHLineCnt;
}
};
void CBarChart::CGDIGrid::SetColor(COLORREF color)
{
// Reset grid pen
if (m_penGrid.GetSafeHandle())
{
m_penGrid.DeleteObject();
}
m_penGrid.CreatePen(PS_SOLID, 1, color);
}
///////////////////////////////////////////////////////////////////////
// CChartBar Class
//
// This class is responsible for for drawing bars and
// performing required calculation for the job.
//
///////////////////////////////////////////////////////////////////////
CBarChart::CChartBar::CChartBar()
{
m_nBarWidth = BAR_DEFAULT_WIDTH;
m_nBarGap = BAR_DEFAULT_GAP;
m_sBarPicSize = CSize(0, 0);
m_sBarPicSize.cy = 0;
m_colorChartBK = RGB(255, 255, 255);
m_pFontOld = NULL;
ZeroMemory(&m_lf, sizeof(m_lf));
CreateLabelFont();
}
CBarChart::CChartBar::~CChartBar()
{
m_chartData.RemoveAll();
if (m_font.GetSafeHandle())
{
m_font.DeleteObject();
}
}
void CBarChart::CChartBar::RemoveAll()
{
m_chartData.RemoveAll();
m_sBarPicSize.cx = 0;
m_sBarPicSize.cy = 0;
}
void CBarChart::CChartBar::RemoveAt(int nIndex)
{
m_chartData.RemoveAt(nIndex);
m_sBarPicSize.cx = m_chartData.GetCount() * (m_nBarWidth + m_nBarGap);
}
void CBarChart::CChartBar::CreateLabelFont()
{
if (m_font.GetSafeHandle())
{
m_font.DeleteObject();
}
strcpy(m_lf.lfFaceName,"Tahoma");
m_lf.lfHeight=-10;
m_lf.lfWidth=0;
m_lf.lfEscapement = 0;
m_lf.lfOrientation = 0;
m_lf.lfItalic = 0;
m_lf.lfUnderline = 0;
m_lf.lfStrikeOut = 0;
m_lf.lfWeight = 400;
m_lf.lfCharSet = ARABIC_CHARSET;
m_lf.lfOutPrecision = OUT_STROKE_PRECIS;
m_lf.lfClipPrecision=2;
m_lf.lfQuality=1;
m_lf.lfPitchAndFamily=2;
// Create font
m_font.CreateFontIndirect(&m_lf);
}
void CBarChart::CChartBar::AddBar(double udValue,CString szLabel, COLORREF color)
{
m_chartData.Add(szLabel, udValue, color);
m_sBarPicSize.cx = m_chartData.GetCount() * (m_nBarWidth + m_nBarGap);
}
void CBarChart::CChartBar::Draw(CDC* pDC, CRect& rcBound)
{
m_sBarPicSize.cy = rcBound.Height()-GRID_FRAME_HEIGHT;
// Draw all bars and labels one by one
DrawBars(pDC, rcBound);
}
void CBarChart::CChartBar::SetBkColor(COLORREF color)
{
m_colorChartBK = color;
}
int CBarChart::CChartBar::GetBarHeight()
{
return m_sBarPicSize.cy;
}
int CBarChart::CChartBar::GetBarWidth()
{
return m_sBarPicSize.cx;
}
void CBarChart::CChartBar::DrawBars(CDC* pDC, CRect& rcBound)
{
double nHeight = 0;
int r1,g1,b1;
int r2,g2,b2;
int r,g,b;
COLORREF colorG, colorEnd, colorSmooth, colorBorder;
int x = 0, y = 0;
CString str;
int cy = m_sBarPicSize.cy;
// If there is a title
// if ()
// {
cy -= CHART_TITLE_HEIGHT;
// }
if (m_bShowBarText)
{
cy -= BAR_TXT_PERCENT_HEIGHT;
}
if (m_bShowLabel)
{
cy -= BAR_TXT_LABEL_HEIGHT;
pDC->FillSolidRect(rcBound.left,
rcBound.bottom - BAR_TXT_LABEL_HEIGHT - CHART_TITLE_HEIGHT -1,
rcBound.right,
rcBound.bottom - CHART_TITLE_HEIGHT, m_colorChartBK);
}
for (int i = 0; i<m_chartData.GetCount();i++)
{
colorBorder = DifColor(m_chartData.GetColor(i), CHART_BORDER_DARKNESS);
colorEnd = DifColor(m_chartData.GetColor(i), CHART_BORDER_DARKNESS - 14);
colorSmooth = OrColor (colorBorder, m_colorChartBK, 40); // A correction color to smooth top 2 rounded edges of the border
nHeight = (m_chartData.GetValue(i) * cy)/
(m_chartData.GetMaxValue());
x = i*(m_nBarWidth + m_nBarGap);
y = m_sBarPicSize.cy - (int) nHeight -
(m_bShowLabel*BAR_TXT_LABEL_HEIGHT) - CHART_TITLE_HEIGHT;
// Center bars
m_rMargin = (double)(rcBound.Width() - m_sBarPicSize.cx)/2.0;
x += (int)m_rMargin;
pDC->FillSolidRect( x, y,
m_nBarWidth,(int)nHeight,
colorBorder);
// Draw a gradient, thanks to Nishant.S
r1 = GetRValue(colorEnd);
g1 = GetGValue(colorEnd);
b1 = GetBValue(colorEnd);
r2 = GetRValue(m_chartData.GetColor(i));
g2 = GetGValue(m_chartData.GetColor(i));
b2 = GetBValue(m_chartData.GetColor(i));
// Don't corrupt border by over painting the gradient
nHeight-=2;
// Draw gradient
for(int j=1;j<=m_nBarWidth-2;j++)
{
r = r1 + (j * (r2-r1) / m_nBarWidth);
g = g1 + (j * (g2-g1) / m_nBarWidth);
b = b1 + (j * (b2-b1) / m_nBarWidth);
if (j<m_nBarWidth/2) {
colorG = OrColor(RGB(r,g,b),RGB(255,255,255),(BAR_REFLECT_AMOUNT + 5*j)>100?
100:(BAR_REFLECT_AMOUNT + 5*j));
} else {
colorG = RGB(r,g,b);
}
pDC->FillSolidRect(j + x, y+1, 1,(int)nHeight,colorG);
}
// Return borders to usual
nHeight+=2;
// Do some Corrections
pDC->SetPixel(x, y, m_colorChartBK);
pDC->SetPixel(x + m_nBarWidth-1, y,m_colorChartBK);
// Smooth these pixels
pDC->SetPixel(x + 1, y, colorSmooth);
pDC->SetPixel(x, y+1, colorSmooth);
pDC->SetPixel(x + m_nBarWidth-2, y, colorSmooth);
pDC->SetPixel(x + m_nBarWidth-1, y+1, colorSmooth);
// Repair these pixels
pDC->SetPixel(x + m_nBarWidth-2, y + 1, colorBorder);
pDC->SetPixel(x + 1, y + 1,colorBorder);
// Add a Percentage/Value at the top of each bar
if (m_bShowBarText || m_bShowLabel)
{
pDC->SetBkMode(TRANSPARENT);
m_pFontOld = (CFont*) pDC->SelectObject(&m_font);
if (m_bShowBarText)
{
// If we shall display percentage
if (m_nBarTextType== 0 )
{
str.Format("%0.01f%%", (m_chartData.GetValue(i)*100)/m_chartData.GetMaxValue());
pDC->DrawText(str, CRect(x, y - BAR_TXT_PERCENT_HEIGHT, x+ m_nBarWidth + m_nBarGap-1, y),
DT_LEFT | DT_SINGLELINE | DT_VCENTER);
}
else if (m_nBarTextType==1) // Draw value at the top of the bar
{
str.Format("%0.02f", m_chartData.GetValue(i));
pDC->DrawText(str, CRect(x, y - BAR_TXT_PERCENT_HEIGHT, x+ m_nBarWidth+ m_nBarGap-1, y),
DT_LEFT | DT_SINGLELINE | DT_VCENTER);
}
}
if (m_bShowLabel)
{
str = m_chartData.GetLabel(i);
pDC->DrawText(str, CRect(x, y + (int)nHeight , x+ m_nBarWidth+ m_nBarGap-1, y + (int)nHeight + BAR_TXT_LABEL_HEIGHT),
DT_LEFT | DT_SINGLELINE | DT_VCENTER);
// If displaying a % at the top of each bar
/* if (m_nBarTextType==0)
{
str.Format("%0.02f", m_chartData.GetValue(i));
pDC->DrawText(str, CRect(0, y - BAR_TXT_PERCENT_HEIGHT, BAR_TXT_VLABEL_MARGIN, y),
DT_LEFT | DT_SINGLELINE | DT_VCENTER);
}*/
}
pDC->SelectObject(m_pFontOld);
}
}
}
void CBarChart::CChartBar::ShowLabel(BOOL bShow)
{
m_bShowLabel = bShow;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -