Рисование полупрозрачного дочернего окна с изображением на родительском окне
Мне нужно сделать анимацию птиц в WS_OVERLAPPED
окно (как показано ниже). Анимация представлена 8 изображениями:
Синий цвет на изображении (который RGB(0, 255, 255)
) должен быть прозрачным (см. скриншот ниже).
Я хотел сделать это с помощью CreateWindowEx()
(птица будет представлена слоистым окном) с WS_EX_LAYERED
аргумент. К сожалению птица должна быть WS_CHILD
, смешивание WS_EX_LAYERED | WS_CHILD
не является законным в Windows 7:
Windows 8: стиль WS_EX_LAYERED поддерживается для окон верхнего уровня и дочерних окон. Предыдущие версии Windows поддерживают WS_EX_LAYERED только для окон верхнего уровня.
Окончательный эффект должен выглядеть следующим образом (я уже нарисовал фон окна - единственная проблема - птица):
Как я могу добиться этого эффекта? Как оживить птицу в родительском окне?
Если у вас есть идеи, как реализовать анимацию птиц с прозрачным фоновым цветом, пожалуйста, поделитесь.
2 ответа
Я наконец узнал, как это сделать. Это довольно сложно.
Полное описание решения доступно здесь - http://www.winprog.org/tutorial/transparency.html.
Для польских читателей здесь отличный перевод.
Простая идея вкратце:
Создание растровых изображений с прозрачными участками выглядит довольно просто и включает использование черно-белого маскирующего изображения в дополнение к цветному изображению, которое мы хотим видеть прозрачным.
Следующие условия должны быть выполнены для правильной работы эффекта: во-первых, цветное изображение должно быть черным во всех областях, которые мы хотим отобразить как прозрачные. И во-вторых, изображение маски должно быть белым в областях, которые мы хотим прозрачными, и черным в других местах. Цветные и маскирующие изображения отображаются как два самых левых изображения в примере изображения на этой странице.
Простое решение вкратце:
#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;
}
Функция, которая отвечает за создание растровой маски:
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;
}
Поскольку анимация выполняется даже тогда, когда нет взаимодействия с окном, нам понадобится таймер:
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;