2013-03-10 121 views
3

我需要在WS_OVERLAPPED窗口中進行鳥動畫(如下所示)。動畫是通過8個圖像表示:在父窗口繪製帶有圖像的半透明子窗口

Animation

藍顏色的圖像中(這是RGB(0, 255, 255))必須是透明的(參見下圖)。

我想用CreateWindowEx()(鳥會用分層窗口表示)與WS_EX_LAYERED的參數來做到這一點。不幸的是,鳥兒必須是WS_CHILD。在混合WS_EX_LAYERED | WS_CHILDis not legal Windows 7的

的Windows 8:WS_EX_LAYERED風格是支持頂層窗口和子窗口。以前的Windows版本僅支持頂級窗口WS_EX_LAYERED

最終的效果應該是這樣的(我已經畫窗口的背景 - 唯一的問題是鳥):

enter image description here

我怎樣才能達到這種效果呢?如何在父窗口中動畫鳥?
如果你有任何想法如何實現具有透明背景顏色的鳥類動畫,請分享。

回答

2

我終於找到了如何做到這一點。這非常棘手。

該解決方案的完整說明可在此處獲得 - winprog.org/tutorial/transparency.html
這裏的波蘭讀者是great translation

簡要

簡單的想法:

給予的位圖具有透明部分的外觀是非常簡單的,涉及除採用了黑色和白色口罩圖像來,我們想看看彩色圖像透明

要使效果正常工作,需要滿足以下條件:首先,彩色圖像在我們想要顯示爲透明的所有區域中必須爲黑色。第二,蒙版圖像必須在我們想要透明的區域爲白色,而在其他地方爲黑色。顏色和蒙版圖像顯示爲此頁面上示例圖片中最左側的兩個圖像。

在簡短簡單的解決方案:

#define TRANSPARENCY_COLOR RGB(0, 255, 255) 

birdBmp = (HBITMAP) LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1)); 
hbmpMask = CreateBitmapMask(birdBmp, TRANSPARENCY_COLOR); 

繪畫:

case WM_PAINT: 
{ 
    hdc = BeginPaint(hWnd, &ps); 

    HDC birdMaskHdc = CreateCompatibleDC(hdc); 

    BITMAP bmInfo; 
    GetObject(birdBmp, sizeof(bmInfo), &bmInfo); 

    HBITMAP hbmpOld = (HBITMAP) SelectObject(birdMaskHdc, hbmpMask); 

    BitBlt(hdc, 0, 0, bmInfo.bmWidth, bmInfo.bmHeight, birdMaskHdc, 0, 0, SRCAND); 
    SelectObject(birdMaskHdc, birdBmp); 
    BitBlt(hdc, 0, 0, bmInfo.bmWidth, bmInfo.bmHeight, birdMaskHdc, 0, 0, SRCPAINT); 

    SelectObject(birdMaskHdc, hbmpOld); 
    DeleteDC(birdMaskHdc); 

    EndPaint(hWnd, &ps); 
    break; 
} 

清洗:

case WM_DESTROY: 
{ 
    DeleteObject(hbmpMask); 
    DeleteObject(birdBmp); 
    PostQuitMessage(0); 
    break; 
} 

功能,其負責對C reating位掩碼:

HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent) 
{ 
    HDC hdcMem, hdcMem2; 
    HBITMAP hbmMask, hbmOld, hbmOld2; 
    BITMAP bm; 

    GetObject(hbmColour, sizeof(BITMAP), & bm); 
    hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL); 

    hdcMem = CreateCompatibleDC(NULL); 
    hdcMem2 = CreateCompatibleDC(NULL); 

    hbmOld =(HBITMAP) SelectObject(hdcMem, hbmColour); 
    hbmOld2 =(HBITMAP) SelectObject(hdcMem2, hbmMask); 

    SetBkColor(hdcMem, crTransparent); 

    BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); 
    BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT); 

    SelectObject(hdcMem, hbmOld); 
    SelectObject(hdcMem2, hbmOld2); 
    DeleteDC(hdcMem); 
    DeleteDC(hdcMem2); 

    return hbmMask; 
} 
2

由於動畫時,有與窗口沒有互動,我們需要一個計時器甚至做到:

case WM_CREATE: 
    // load resources 
    SetTimer(hwnd, 0, 250, NULL); // set timer to 250 ms 
return 0; 

... 

case WM_DESTROY: 
    KillTimer(hwnd, 0); 
    // release the resources 
return 0; 

我們可以無效整個窗口的每個時鐘滴答,但它會更好重繪只需要部分。我們也將在這裏更新當前幀編號:

case WM_TIMER: 
    frame_number++; 
    if (frame_number >= 8) 
     frame_number = 0; 

    RECT rc = { 30, 30, 80, 80 }; // a rectangle from (30,30) to (80,80) 
    InvalidateRect(hwnd, &rc, FALSE); 
return 0; 

然後,我們在WM_PAINT處理程序繪製當前幀:

case WM_PAINT: 
    // draw the sky 

    SelectObject(hDCMem, hBird); 
    TransparentBlt(hDC, 30, 30, 50, 50, hDCMem, frame_number * 51, 0, 50, 50, RGB(0, 255, 255)); // 51 is 50 (side of a bird frame) + 1 (gap between the frames) 

    // draw the rest 
return 0; 
+0

我忘了提,'TransparentBlt()'在這個項目中(我不知道爲什麼)禁止。 – 2013-03-10 23:57:40

+1

@ patryk.beza,'BitBlt'也被禁止?如果不是,您可以使用'TransparentBlt'的Wine實現:http://source.winehq.org/git/wine.git/blob/HEAD:/dlls/gdi32/bitblt.c#l827?如果是的話,你如何繪製背景? – Joulukuusi 2013-03-11 10:50:58

+0

我使用未被禁止的BitBlt繪製背景。 – 2013-03-11 22:36:10