⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 superprogressctrl.cpp

📁 采用渐变色表示的进度条
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////
// SuperProgressCtrl.cpp
// Implementation file of the CSuperProgressCtrlCtrl class

#include "stdafx.h"
#include "SuperProgressCtrl.h"

///////////////////////////////////////////////////////////////////
// CSuperProgressCtrl implementation
//

/////////////////////////////////////////////////////////////////////
// Converts a bitmap to a region
//
//	BitmapToRegion :	Create a region from the "non-transparent" pixels of a bitmap
//	Author :			Jean-Edouard Lachand-Robert (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
//
//	hBmp :				Source bitmap
//	cTransparentColor :	Color base for the "transparent" pixels (default is black)
//	cTolerance :		Color tolerance for the "transparent" pixels.
//
//	A pixel is assumed to be transparent if the value of each of its 3 components (blue, green and red) is 
//	greater or equal to the corresponding value in cTransparentColor and is lower or equal to the 
//	corresponding value in cTransparentColor + cTolerance.
//
static
HRGN BitmapToRegion(HBITMAP hBmp, COLORREF cTransparentColor = 0,
					COLORREF cTolerance = 0x101010)
{
	HRGN hRgn = NULL;

	if(hBmp)
	{
		// Create a memory DC inside which we will scan the bitmap content
		HDC hMemDC = CreateCompatibleDC(NULL);
		if(hMemDC)
		{
			// Get bitmap size
			BITMAP bm;
			GetObject(hBmp, sizeof(bm), &bm);

			// Create a 32 bits depth bitmap and select it into the memory DC 
			BITMAPINFOHEADER RGB32BITSBITMAPINFO = {	
					sizeof(BITMAPINFOHEADER),	// biSize 
					bm.bmWidth,					// biWidth; 
					bm.bmHeight,				// biHeight; 
					1,							// biPlanes; 
					32,							// biBitCount 
					BI_RGB,						// biCompression; 
					0,							// biSizeImage; 
					0,							// biXPelsPerMeter; 
					0,							// biYPelsPerMeter; 
					0,							// biClrUsed; 
					0							// biClrImportant; 
			};
			VOID * pbits32; 
			HBITMAP hbm32 = CreateDIBSection(hMemDC, (BITMAPINFO *)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0);
			if(hbm32)
			{
				HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32);

				// Create a DC just to copy the bitmap into the memory DC
				HDC hDC = CreateCompatibleDC(hMemDC);
				if(hDC)
				{
					// Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits)
					BITMAP bm32;
					GetObject(hbm32, sizeof(bm32), &bm32);
					while(bm32.bmWidthBytes % 4)
						bm32.bmWidthBytes++;

					// Copy the bitmap into the memory DC
					HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
					BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);

					// For better performances, we will use the ExtCreateRegion() function to create the
					// region. This function take a RGNDATA structure on entry. We will add rectangles by
					// amount of ALLOC_UNIT number in this structure.
					#define ALLOC_UNIT	100
					DWORD maxRects = ALLOC_UNIT;
					HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
					RGNDATA *pData = (RGNDATA *)GlobalLock(hData);
					pData->rdh.dwSize = sizeof(RGNDATAHEADER);
					pData->rdh.iType = RDH_RECTANGLES;
					pData->rdh.nCount = pData->rdh.nRgnSize = 0;
					SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);

					// Keep on hand highest and lowest values for the "transparent" pixels
					BYTE lr = GetRValue(cTransparentColor);
					BYTE lg = GetGValue(cTransparentColor);
					BYTE lb = GetBValue(cTransparentColor);
					BYTE hr = min(0xff, lr + GetRValue(cTolerance));
					BYTE hg = min(0xff, lg + GetGValue(cTolerance));
					BYTE hb = min(0xff, lb + GetBValue(cTolerance));

					// Scan each bitmap row from bottom to top (the bitmap is inverted vertically)
					BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
					for(int y = 0; y < bm.bmHeight; y++)
					{
						// Scan each bitmap pixel from left to right
						for(int x = 0; x < bm.bmWidth; x++)
						{
							// Search for a continuous range of "non transparent pixels"
							int x0 = x;
							LONG *p = (LONG *)p32 + x;
							while(x < bm.bmWidth)
							{
								BYTE b = GetRValue(*p);
								if(b >= lr && b <= hr)
								{
									b = GetGValue(*p);
									if(b >= lg && b <= hg)
									{
										b = GetBValue(*p);
										if(b >= lb && b <= hb)
											// This pixel is "transparent"
											break;
									}
								}
								p++;
								x++;
							}

							if(x > x0)
							{
								// Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region
								if(pData->rdh.nCount >= maxRects)
								{
									GlobalUnlock(hData);
									maxRects += ALLOC_UNIT;
									hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
									pData = (RGNDATA *)GlobalLock(hData);
								}
								RECT *pr = (RECT *)&pData->Buffer;
								SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);
								if(x0 < pData->rdh.rcBound.left)
									pData->rdh.rcBound.left = x0;
								if(y < pData->rdh.rcBound.top)
									pData->rdh.rcBound.top = y;
								if(x > pData->rdh.rcBound.right)
									pData->rdh.rcBound.right = x;
								if(y+1 > pData->rdh.rcBound.bottom)
									pData->rdh.rcBound.bottom = y+1;
								pData->rdh.nCount++;

								// On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
								// large (ie: > 4000). Therefore, we have to create the region by multiple steps.
								if(pData->rdh.nCount == 2000)
								{
									HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
									if(hRgn)
									{
										CombineRgn(hRgn, hRgn, h, RGN_OR);
										DeleteObject(h);
									}
									else
										hRgn = h;
									pData->rdh.nCount = 0;
									SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
								}
							}
						}

						// Go to next row (remember, the bitmap is inverted vertically)
						p32 -= bm32.bmWidthBytes;
					}

					// Create or extend the region with the remaining rectangles
					HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
					if(hRgn)
					{
						CombineRgn(hRgn, hRgn, h, RGN_OR);
						DeleteObject(h);
					}
					else
						hRgn = h;

					// Clean up
					GlobalFree(hData);
					SelectObject(hDC, holdBmp);
					DeleteDC(hDC);
				}

				DeleteObject(SelectObject(hMemDC, holdBmp));
			}

			DeleteDC(hMemDC);
		}	
	}

	return hRgn;
}

///////////////////////////////////////////////////////////////////
// InflateRegion - Inflates a region by the x and y values
// specified in nXInflate and nYInflate
// Creates a new region that represents the inflated region
// (retains the contents of the old region)
// Returns NULL if unsuccessfull
static HRGN InflateRegion(HRGN hRgn, int nXInflate, int nYInflate)
{
	// Local Variables
	LPRGNDATA lpData;	// The RGNDATA structure
	LPRECT lpRect;		// Pointer to the array of RECT structures
	DWORD BufSize;		// The amount of memory required
	DWORD i;			// General index variable
	HRGN hRgnNew;		// The newly created region

	// Get the number of rectangles in the region
	BufSize = GetRegionData(hRgn, 0, NULL);
	if(BufSize == 0)
		return NULL;
	// Allocate memory for the RGNDATA structure
	lpData = (LPRGNDATA)malloc(BufSize);
	// Set the location of the RECT structures
	lpRect = (LPRECT)(lpData->Buffer);
	// Get the region data
	if(!GetRegionData(hRgn, BufSize, lpData))
	{
		free(lpData);
		return NULL;
	}
	// Expand (or contract) all the rectangles in the data
	for(i=0; i<lpData->rdh.nCount; i++)
		InflateRect(&lpRect[i], nXInflate, nYInflate);
	// Create the new region
	hRgnNew = ExtCreateRegion(NULL, lpData->rdh.nCount, lpData);
	free((void*)lpData);
	return hRgnNew;
}

/////////////////////////////////////////////////////////////////////////////
// CSuperProgressCtrl

CSuperProgressCtrl::CSuperProgressCtrl()
{
}

CSuperProgressCtrl::~CSuperProgressCtrl()
{
}


BEGIN_MESSAGE_MAP(CSuperProgressCtrl, CWnd)
	//{{AFX_MSG_MAP(CSuperProgressCtrl)
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSuperProgressCtrl message handlers

CString CSuperProgressCtrl::s_Class = "";
void CSuperProgressCtrl::RegisterClass()
{
	// Register the window class
	s_Class = AfxRegisterWndClass(CS_CLASSDC,
		AfxGetApp()->LoadStandardCursor(IDC_ARROW),
		(HBRUSH)(COLOR_BTNFACE+1), NULL);
}

BOOL CSuperProgressCtrl::Create(CWnd* pParent, int x, int y,
							HBITMAP hbmArea, UINT nID)
{
	// Local Variables
	BITMAP bm;
	BOOL bRet;
	HRGN hRgn;

	// Get the dimensions of the given bitmap
	if(GetObject((HGDIOBJ)hbmArea, sizeof(BITMAP), (void*)&bm) == 0)
		return FALSE;
	// Create the window
	bRet = CWnd::Create(s_Class, NULL, WS_VISIBLE | WS_CHILD,
		CRect(x, y, x+bm.bmWidth-1, y+bm.bmHeight-1), pParent,
		nID, NULL);
	// Set the various member variables
	m_nMin = 0;			// Default minimum is 0
	m_nMax = 100;		// Default maximum is 100
	m_nPosition = 0;	// Initial position is at 0
	m_nStep = 10;		// Default step is 10
	m_Colour1 = RGB(0,0,255);	// Default start colour is blue
	m_Colour2 = RGB(255,0,0);	// Default end colour is red
	m_Background = GetSysColor(COLOR_3DFACE);	// Dialog Background
	m_nFillStyle = SP_FILL_HORZGRAD;	// Horizontal Gradient
	// If the window was created successfully, set the window region
	if(bRet)
	{
		m_hbmArea = hbmArea;
		m_hRegion = BitmapToRegion(hbmArea, RGB(255,255,255), 0x000000);
		hRgn = InflateRegion(m_hRegion, 1, 1);
		SetWindowRgn(m_hWnd, hRgn, TRUE);
		// We don't need to delete the region,
		// Windows does it for us when the
		// window is destroyed
	}
	// Return the status of the window creation
	return bRet;
}

void CSuperProgressCtrl::SetRange(int nMin, int nMax)
{
	// Make sure that max > min
	ASSERT(nMax > nMin);
	// Set the maximum and minimum values
	m_nMin = nMin;
	m_nMax = nMax;
	// Invalidate the window
	::InvalidateRgn(m_hWnd, m_hRegion, FALSE);
}

int CSuperProgressCtrl::SetPos(int nPos)
{
	int oldpos = m_nPosition;
	// Make sure that min <= pos <= max
	ASSERT((nPos >= m_nMin) && (nPos <= m_nMax));
	// Set the new position
	m_nPosition = nPos;
	// Invalidate the window
	if(m_nPosition != oldpos);
		::InvalidateRgn(m_hWnd, m_hRegion, FALSE);
	return oldpos;
}

int CSuperProgressCtrl::OffsetPos(int nOffset)
{
	int oldpos = m_nPosition;
	// Make sure that min <= pos <= max
	ASSERT(((nOffset+m_nPosition) >= m_nMin) &&
		((nOffset+m_nPosition) <= m_nMax));
	// Set the new position
	m_nPosition += nOffset;
	// Invalidate the window
	if(m_nPosition != oldpos)
		::InvalidateRgn(m_hWnd, m_hRegion, FALSE);
	return oldpos;
}

int CSuperProgressCtrl::SetStep(int nStep)
{
	int oldpos = m_nStep;
	// Make sure that step is less than
	// the difference between max and min
	ASSERT(nStep <= (m_nMax - m_nMin + 1));
	// Set the new step value
	m_nStep = nStep;
	return oldpos;
}

int CSuperProgressCtrl::StepIt()
{
	int oldpos = m_nPosition;
	// Only step if the new position is in range

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -