Environment: VC6
Introduction
This is a very simple example to implement a skin in a dialog-based application. The code is actually written by a friend of mine ([email protected]), so thanks go to him. I am just showing you how simple it is to use. Also, thanks to Davide Calabro, who gave me permission to use his CButtonST
class.
Example
In my example, I use a simple, dialog-based app called “Skin.” Import a bitmap you like for your dialog. In our case it’s labeled IDB_MAIN
. Create the following variables and functions in your dialog’s header file.
CSkinDlg : public CDialog
{
public: CSkinDlg();
HBITMAP m_hBmp;
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_hWndRgn=DIBToRgn(m_hBmp,0x00ff00,FALSE);
}
Insert the function called HRGN DIBToRgn(HBITMAP hBmp, COLORREF BkColor, BOOL Direct)
into your Dialog class and paste the following code into 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) { //create 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 orginal 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 that can change big //allocate 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 struct 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; }
Add a handler for the ON_WM_ERASEBKND
message to erase the dialog’s background:
BOOL CSkinDlg::OnEraseBkgnd(CDC* pDC) { if(m_hBmp) { BITMAP bm; GetObject(m_hBmp,sizeof(bm),&bm); HDC hMemdc=CreateCompatibleDC(pDC->m_hDC); if(hMemdc) { HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemdc,m_hBmp); if(hOldBmp) { BitBlt(pDC->m_hDC, 0,0, bm.bmWidth, bm.bmHeight, hMemdc, 0,0, SRCCOPY); SelectObject(hMemdc,hOldBmp); DeleteDC(hMemdc); DeleteObject(hOldBmp); return TRUE; } else DeleteDC(hMemdc); } } return CDialog::OnEraseBkgnd(pDC); }
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 }
The Minimise and Close boxes on the dialog are implemented using Davide Calabro’s CButtonST
class.
That’s it! Run your app and you will see your great skin. This article is provided by www.codefinger.de.