Trong ví dụ này một dialog được gọi là Skin.Chọn một hình bitmap cho dialog của bạn
Mã lệnh (C++) |
CSkinDlg : public CDialog
{ public: CSkinDlg(); HBITMAP m_hBmp; HRGN m_hWndRgn; HRGN DIBToRgn(HBITMAP hBmp,COLORREF BkColor,BOOL Direct); // Handle the Skin . . . } Trong Constructor Sẽ làm những việc sau đây: 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); } Thêm một hàm HRGN DIBToRgn(HBITMAP hBmp, COLORREF BkColor, BOOL Direct)đến lớp Dialog của bạn và dán đoạn code sau: 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 which 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; } thêm một handler cho thông báo(message) ON_WM_ERASEBKND để xoá nền của dialog: 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); } Trong OnInitDialog, Thêm dòng code: BOOL CSkinDlg::OnInitDialog() { . . . // Show the Skin if(m_hWndRgn) SetWindowRgn(m_hWndRgn,TRUE); return TRUE; } |