Thursday, September 19, 2024

An easy way to use Skins in a Dialog based Application

This is a very simple example to implement a skin in a Dialog Based Application. The Code is actually written by a friend ( sun@codefinger.de ) of me, so I am not the one who wrote the code, thanks to him. I am just showing you how simple it is to use. Also thanks to “Davide Calabro” who gave me the Permission to use the CButtonST class.

Contents:

Source Code
A Simple Example

Example:

In My Example i am using a simple Dialog based App called “Skin”. Import a Bitmap you like for your Dialog. In our case its the IDB_MAIN. Create the following variables and function in your Dialog header file.

CSkinDlg : public CDialog
{
public:
        CSkinDlg();
	HBITMAP m_hBmp;
	HRGN m_hClientRgn;
	HRGN m_hWndRgn;
	HRGN DIBToRgn(HBITMAP hBmp,COLORREF BkColor,BOOL Direct); // Handle the Skin
	.
	.
	.

In the Constructor do the following:

CSkinDlg::CSkintDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSkinDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CSkinDlg)
	//}}AFX_DATA_INIT
                     m_hBmp=(HBITMAP)LoadImage(AfxGetApp()->m_hInstance,
                               MAKEINTRESOURCE(IDB_MAIN),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
	m_hClientRgn=CreateEllipticRgn(33,34,34,35);
	m_hWndRgn=DIBToRgn(m_hBmp,0x00ff00,FALSE);
}

Insert the function called HRGN DIBToRgn(HBITMAP hBmp, COLORREF BkColor, BOOL Direct) to your Dialog class and paste the following code to it.

HRGN CSkinDlg ::DIBToRgn(HBITMAP hBmp, COLORREF BkColor, BOOL Direct)
{
// use to return the handle of the HGRN
  HRGN hRgn = NULL;					
#define MAX_ALLOC_RECTS  100
//the difference of the color
COLORREF  Tolerance=0x00101010;
if (hBmp)
{
 //creat the dib to save the dc
 HDC hMemDC = CreateCompatibleDC(NULL);		
 if (hMemDC)
 {
 BITMAP bm;
 //get the info of the bitmap
 GetObject(hBmp, sizeof(bm), &bm);	




	BITMAPINFOHEADER BmpInfoh = {				//the struct of the bitmap
			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;
	};

	//design a void point to point to the bitmap
	LPVOID pBit32; 
	//creat a DIB
	HBITMAP hDib32 = CreateDIBSection(hMemDC, 
			(BITMAPINFO *)&BmpInfoh, 
			DIB_RGB_COLORS, &pBit32, NULL, 0);
	if (hDic32)
	{
		//copy dib to DC
		HBITMAP hOldib32 = (IBITMAP)SelectObject(hMemDC, hDib32);
		// create a DC to save orgin bitmap
		HDC hDC = CreateCompatibleDC(hMemDC);
		if (hDC)
		{

			BITMAP bm32;
			// get the new 34 bit Dib size
			GetObject(hDib32, sizeof(bm32), &bm32);
			//make sure the 32Dib's every line pilex's is 4 's times
			while (bm32.bmWidthBytes % 4)
				bm32.bmWidthBytes++;
			//copy the orginal dib to DC
			HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
			//copy dib to memory DC
			BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);
			DWORD MaxRects = MAX_ALLOC_RECTS;
			SYSTEM_INFO  Sysinfo;
			//get memory size
			GetSystemInfo(&Sysinfo);
			//make a stack which can chang big
			//alloct memory
			HANDLE 
hRcData=HeapCreate(HEAP_GENERATE_EXCEPTIONS,Sysinfo.dwPageSize, 0);
			RGNDATA * pRcData=(RGNDATA*)HeapAlloc(hRcData,HEAP_ZERO_MEMORY,
				sizeof(RGNDATAHEADER)+sizeof(RECT)*MaxRects);
			 //fill the the RGNDATA struck
			pRcData->rdh.dwSize = sizeof(RGNDATAHEADER);
			pRcData->rdh.iType = RDH_RECTANGLES;
			pRcData->rdh.nCount = pRcData->rdh.nRgnSize = 0;
			SetRect(&pRcData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
	            		BYTE hr,hg,hb,lr,lg,lb;
			switch(BkColor)
			{

			case RGB(255,255,255):	//if the bkcolor is white
				hr = GetRValue(BkColor);
				hg = GetGValue(BkColor);
				hb = GetBValue(BkColor);
				lr = min(0xff, hr - GetRValue(Tolerance));
				lg = min(0xff, hg - GetGValue(Tolerance));
				lb = min(0xff, hb - GetBValue(Tolerance));
				break;
				case RGB(0,0,0):	//if the bkcolor is black
				lr = GetRValue(BkColor);
				lg = GetGValue(BkColor);
				lb = GetBValue(BkColor);
				hr = min(0xff, lr + GetRValue(Tolerance));
				hg = min(0xff, lg + GetGValue(Tolerance));
				hb = min(0xff, lb + GetBValue(Tolerance));
				break;

			default:		//if the bkcolor is other color
				Tolerance=0x111111;
				lr =max(0, GetRValue(BkColor)-GetRValue(Tolerance));
				lg = max(0,GetGValue(BkColor)-GetGValue(Tolerance));
				lb = max(0,GetBValue(BkColor)-GetBValue(Tolerance));
				hr=min(0xff,GetRValue(BkColor)+GetRValue(Tolerance));
				hg=min(0xff,GetGValue(BkColor)+GetGValue(Tolerance));
				hb=min(0xff,GetBValue(BkColor)+GetBValue(Tolerance));
				break;
			}
			// Get the bit point and do the search
			BYTE *pBits = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
			for (int y = 0; y < bm.bmHeight; y++)
			{
				for (int x = 0; x < bm.bmWidth; x++)
				{
					int x0 = x;
					DWORD *pColor = (DWORD *)pBits + x;
					BYTE dr,dg,db;
					while (x < bm.bmWidth)
					{
						dr=GetRValue(*pColor);
						dg=GetGValue(*pColor);
						db=GetBValue(*pColor);
if ((dr>= lr && dr<= hr)&&(dg>=lg&&dg<=hg)&&(db>=lb&&db<=hb))
						{
							if(Direct)
								break;
							else
							{
								pColor++;
								x++;
							}
					  	}
						else if(Direct)
						{
							pColor++;
							x++;
						}
						else
							break;
						}
					if (x > x0)
					{
						if (pRcData->rdh.nCount >= MaxRects)
						{
						MaxRects += MAX_ALLOC_RECTS;
						//re alloc the stack
						pRcData=(RGNDATA*)HeapReAlloc(
						hRcData,HEAP_ZERO_MEMORY,pRcData, 
						sizeof(RGNDATAHEADER)+sizeof(RECT)*MaxRects);
					}

					RECT *pr = (RECT *)&pRcData->Buffer;
					SetRect(&pr[pRcData->rdh.nCount], x0, y, x, y+1);
						pRcData->rdh.rcBound.left = x0;
						pRcData->rdh.rcBound.top = y;
						pRcData->rdh.rcBound.right = x;
						pRcData->rdh.rcBound.bottom = y+1;
						pRcData->rdh.nCount++;
							if (pRcData->rdh.nCount == 3000)
						{	
						HRGN tmphRgn = ExtCreateRegion(NULL,
						sizeof(RGNDATAHEADER) + (sizeof(RECT) * MaxRects),
						pRcData);
						if (hRgn)
							{
						CombineRgn(hRgn, hRgn, tmphRgn, RGN_OR);
								DeleteObject(tmphRgn);
						}
							else
						hRgn = tmphRgn;
						pRcData->rdh.nCount = 0;
						SetRect(&pRcData->rdh.rcBound, 
						MAXLONG, MAXLONG, 0, 0);
					}
				}
			}


				// search next line
			pBits -= bm32.bmWidthBytes;
		}
				HRGN tmphRgn = ExtCreateRegion(NULL, 
				sizeof(RGNDATAHEADER) + (sizeof(RECT) * MaxRects), pRcData);
		if (hRgn)
		{
			CombineRgn(hRgn, hRgn, tmphRgn, RGN_OR);
			DeleteObject(tmphRgn);
		}
		else
			hRgn = tmphRgn;
		// make a rect ,use this rect xor to the  BkColor
		//then we can get the rect we want
		if(!Direct)
		{
			HRGN hRect=CreateRectRgn(0,0,bm.bmWidth,bm.bmHeight);
	                        if(hRect)
			{
				CombineRgn(hRgn,hRgn,hRect,RGN_XOR);
				DeleteObject(hRect);
			}
		    else
				return NULL;
		}
		//release the memory
		HeapFree(hRcData,HEAP_NO_SERIALIZE,pRcData);
		SelectObject(hDC, holdBmp);
		DeleteDC(hDC);
				DeleteObject(holdBmp);
			}
			SelectObject(hMemDC,hOldib32);
			DeleteDC(hMemDC);
			DeleteObject(hOldib32);
			DeleteObject(hDib32);
		}
		else
			DeleteDC(hMemDC);
	}
}
return hRgn;
 }

Overrite the ON_WM_ERASEBKND function to erase the background of the Dialog:

BOOL CSkinDlg::OnEraseBkgnd(CDC* pDC)
{
&nbsp &nbsp if(m_hBmp)
&nbsp&nbsp {
&nbsp&nbsp&nbsp&nbsp BITMAP bm;
&nbsp&nbsp&nbsp&nbsp GetObject(m_hBmp,sizeof(bm),&bm);
&nbsp&nbsp&nbsp&nbsp HDC hMemdc=CreateCompatibleDC(pDC->m_hDC);
&nbsp&nbsp&nbsp&nbsp if(hMemdc)
&nbsp&nbsp&nbsp&nbsp {
&nbsp&nbsp&nbsp HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemdc,m_hBmp);
&nbsp&nbsp&nbsp&nbsp if(hOldBmp)
&nbsp&nbsp&nbsp&nbsp {
&nbsp&nbsp&nbsp BitBlt(pDC->m_hDC,0,0,bm.bmWidth,bm.bmHeight,hMemdc,0,0,SRCCOPY);
&nbsp&nbsp&nbsp SelectObject(hMemdc,hOldBmp);
&nbsp&nbsp&nbsp DeleteDC(hMemdc);
&nbsp&nbsp&nbsp DeleteObject(hOldBmp);
&nbsp&nbsp&nbsp return TRUE;
&nbsp&nbsp &nbsp }
&nbsp&nbsp&nbsp else
&nbsp&nbsp&nbsp DeleteDC(hMemdc);
&nbsp&nbsp&nbsp }
&nbsp&nbsp}
&nbsp&nbspreturn CDialog::OnEraseBkgnd(pDC);
&nbsp}

In your OnInitDialog enter the following code:

BOOL CSkinDlg::OnInitDialog()
{
	.
	.
	.
	// Show the Skin
	if(m_hWndRgn)
		SetWindowRgn(m_hWndRgn,TRUE);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

That`s it ! Run your app and you will see your Great Skin.

Codefinger was founded 2000 by Sonu Kapoor. Sonu has studied E-Commerce in India and currently lives in Germany. After graduation he worked for several companies in Germany. He currently works as a Network Consultant and Software Developer. He has written many applications in various programming languages like VC++, ASP, ASP.NET, XML or XSL. Besides his passion for developing applications, Sonu writes articles for several major websites like Developer.com. He also works as a freelancer for CodeGuru.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles

Content management software. Video marketing statistics.