Windows/MFC
DrawGradient
aucd29
2013. 10. 2. 18:10
[code]여차하면 GDI+를 사용하겠지만 그래도 Gradient가 어떻게 만들어지는 지 알고 있으면 좋을 테니 말이지[/code]
[code]
/////////////////////////////////////////////////////////////////////////////
/*
DrawGradient
Called from OnPaint, it does most of the work of filling in the client
rectangle with the appropriate colors. The normal routine would fill
the entire client rectangle, but we truncate the drawing to reflect
the current position in the progress control
Params
pDC pointer to CPaintDC for rendering
rectClient client rectangle where we should draw
nMaxWidth where we should stop drawing the gradient
*/
/////////////////////////////////////////////////////////////////////////////
void CGradientProgressCtrl::DrawGradient(CPaintDC *pDC, const RECT &rectClient, const int &nMaxWidth, const BOOL &bVertical)
{
RECT rectFill; // Rectangle for filling band
float fStep; // How wide is each band?
CBrush brush; // Brush to fill in the bar
CMemDC memDC(pDC);
// First find out the largest color distance between the start and end colors. This distance
// will determine how many steps we use to carve up the client region and the size of each
// gradient rect.
int r, g, b; // First distance, then starting value
float rStep, gStep, bStep; // Step size for each color
BOOL bSameColor = FALSE; // Handle case if start color == end color
// Get the color differences
r = (GetRValue(m_clrEnd) - GetRValue(m_clrStart));
g = (GetGValue(m_clrEnd) - GetGValue(m_clrStart));
b = (GetBValue(m_clrEnd) - GetBValue(m_clrStart));
// Check to see if colors are same
if((r == 0) && (g == 0) && (b == 0))
{
bSameColor = TRUE;
//Added the three lines below to fix the drawing
//problem which used to occur when both the start
//and end colors are same.
r = GetRValue(m_clrStart);
g = GetGValue(m_clrStart);
b = GetBValue(m_clrStart);
}
int nSteps;
//Select max. possible value for nSteps if the colors are equal
if(bSameColor && m_clrStart == 0)
nSteps = 255;
else // Make the number of steps equal to the greatest distance
nSteps = max(abs(r), max(abs(g), abs(b)));
// Determine how large each band should be in order to cover the
// client with nSteps bands (one for every color intensity level)
if (bVertical)
fStep = (float)rectClient.bottom / (float)nSteps;
else
fStep = (float)rectClient.right / (float)nSteps;
// Calculate the step size for each color
rStep = r/(float)nSteps;
gStep = g/(float)nSteps;
bStep = b/(float)nSteps;
// Reset the colors to the starting position
r = GetRValue(m_clrStart);
g = GetGValue(m_clrStart);
b = GetBValue(m_clrStart);
// Start filling bands
for (int iOnBand = 0; iOnBand < nSteps; iOnBand++)
{
// Fill the vertical control
if (bVertical)
{
::SetRect(&rectFill,
0, // Upper left X
(int)(iOnBand * fStep), // Upper left Y
rectClient.right+1, // Lower right X
(int)((iOnBand+1) * fStep));// Lower right Y
// CDC::FillSolidRect is faster, but it does not handle 8-bit color depth
VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand)));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
// If we are past the maximum for the current position we need to get out of the loop.
// Before we leave, we repaint the remainder of the client area with the background color.
if (rectFill.bottom > nMaxWidth)
{
::SetRect(&rectFill, 0, rectFill.bottom, rectClient.right, rectClient.bottom);
VERIFY(brush.CreateSolidBrush(m_clrBkGround));
memDC.FillRect(&rectFill, &brush);
VERIFY(brush.DeleteObject());
return;
}
}
else // Fill the horizontal control
{
::SetRect(&rectFill,
(int)(iOnBand * fStep), // Upper left X
0, // Upper left Y
(int)((iOnBand+1) * fStep), // Lower right X
rectClient.bottom+1); // Lower right Y
// CDC::FillSolidRect is faster, but it does not handle 8-bit color depth
VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand)));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
// If we are past the maximum for the current position we need to get out of the loop.
// Before we leave, we repaint the remainder of the client area with the background color.
if (rectFill.right > nMaxWidth)
{
::SetRect(&rectFill, rectFill.right, 0, rectClient.right, rectClient.bottom);
VERIFY(brush.CreateSolidBrush(m_clrBkGround));
memDC.FillRect(&rectFill, &brush);
VERIFY(brush.DeleteObject());
return;
}
}
}
}[/code]
[code]
/////////////////////////////////////////////////////////////////////////////
/*
DrawGradient
Called from OnPaint, it does most of the work of filling in the client
rectangle with the appropriate colors. The normal routine would fill
the entire client rectangle, but we truncate the drawing to reflect
the current position in the progress control
Params
pDC pointer to CPaintDC for rendering
rectClient client rectangle where we should draw
nMaxWidth where we should stop drawing the gradient
*/
/////////////////////////////////////////////////////////////////////////////
void CGradientProgressCtrl::DrawGradient(CPaintDC *pDC, const RECT &rectClient, const int &nMaxWidth, const BOOL &bVertical)
{
RECT rectFill; // Rectangle for filling band
float fStep; // How wide is each band?
CBrush brush; // Brush to fill in the bar
CMemDC memDC(pDC);
// First find out the largest color distance between the start and end colors. This distance
// will determine how many steps we use to carve up the client region and the size of each
// gradient rect.
int r, g, b; // First distance, then starting value
float rStep, gStep, bStep; // Step size for each color
BOOL bSameColor = FALSE; // Handle case if start color == end color
// Get the color differences
r = (GetRValue(m_clrEnd) - GetRValue(m_clrStart));
g = (GetGValue(m_clrEnd) - GetGValue(m_clrStart));
b = (GetBValue(m_clrEnd) - GetBValue(m_clrStart));
// Check to see if colors are same
if((r == 0) && (g == 0) && (b == 0))
{
bSameColor = TRUE;
//Added the three lines below to fix the drawing
//problem which used to occur when both the start
//and end colors are same.
r = GetRValue(m_clrStart);
g = GetGValue(m_clrStart);
b = GetBValue(m_clrStart);
}
int nSteps;
//Select max. possible value for nSteps if the colors are equal
if(bSameColor && m_clrStart == 0)
nSteps = 255;
else // Make the number of steps equal to the greatest distance
nSteps = max(abs(r), max(abs(g), abs(b)));
// Determine how large each band should be in order to cover the
// client with nSteps bands (one for every color intensity level)
if (bVertical)
fStep = (float)rectClient.bottom / (float)nSteps;
else
fStep = (float)rectClient.right / (float)nSteps;
// Calculate the step size for each color
rStep = r/(float)nSteps;
gStep = g/(float)nSteps;
bStep = b/(float)nSteps;
// Reset the colors to the starting position
r = GetRValue(m_clrStart);
g = GetGValue(m_clrStart);
b = GetBValue(m_clrStart);
// Start filling bands
for (int iOnBand = 0; iOnBand < nSteps; iOnBand++)
{
// Fill the vertical control
if (bVertical)
{
::SetRect(&rectFill,
0, // Upper left X
(int)(iOnBand * fStep), // Upper left Y
rectClient.right+1, // Lower right X
(int)((iOnBand+1) * fStep));// Lower right Y
// CDC::FillSolidRect is faster, but it does not handle 8-bit color depth
VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand)));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
// If we are past the maximum for the current position we need to get out of the loop.
// Before we leave, we repaint the remainder of the client area with the background color.
if (rectFill.bottom > nMaxWidth)
{
::SetRect(&rectFill, 0, rectFill.bottom, rectClient.right, rectClient.bottom);
VERIFY(brush.CreateSolidBrush(m_clrBkGround));
memDC.FillRect(&rectFill, &brush);
VERIFY(brush.DeleteObject());
return;
}
}
else // Fill the horizontal control
{
::SetRect(&rectFill,
(int)(iOnBand * fStep), // Upper left X
0, // Upper left Y
(int)((iOnBand+1) * fStep), // Lower right X
rectClient.bottom+1); // Lower right Y
// CDC::FillSolidRect is faster, but it does not handle 8-bit color depth
VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand, g + gStep*iOnBand, b + bStep *iOnBand)));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
// If we are past the maximum for the current position we need to get out of the loop.
// Before we leave, we repaint the remainder of the client area with the background color.
if (rectFill.right > nMaxWidth)
{
::SetRect(&rectFill, rectFill.right, 0, rectClient.right, rectClient.bottom);
VERIFY(brush.CreateSolidBrush(m_clrBkGround));
memDC.FillRect(&rectFill, &brush);
VERIFY(brush.DeleteObject());
return;
}
}
}
}[/code]