起動すると、少しずつ濃くなって現れてきます。
完全にアルファが100%となった状態です。
終了するときは徐々に消えていきます。
これは、どのようにするかというと
1.メインウィンドウの拡張ウィンドウスタイルをWS_EX_LAYEREDにする 2.WM_CREATEメッセージが来たらウィンドウのアルファを0にする。 また、SetTimer関数でタイマーを作成します。 3.WM_TIMERメッセージが来たらウィンドウのアルファを少し上げる 4.アルファが255になったらタイマーを殺す 5.終了確認で「はい」と答えたらタイマーを作成する 6.WM_TIMERメッセージが来たらアルファを少しずつ下げる 7.アルファが0になったらDestroyWindow関数でウィンドウを破棄するこんな感じで実現します。では、プログラムを見てみましょう。
// layer02.cpp #define _WIN32_WINNT 0x0500 #define ID_MYTIMER 100 #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "layer02"; //ウィンドウクラス HINSTANCE hInst;_WIN32_WINNTを0x0500以上にdefineするのを忘れないでください。
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; BOOL bRet; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) { if (bRet == -1) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int)msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); wc.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindowEx(WS_EX_LAYERED, szClassName, "猫でもわかるlayer", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 180, //幅 170, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }メインウィンドウの拡張スタイルにWS_EX_LAYEREDを指定します。
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HDC hdc, hdc_mem; HBRUSH hBrush; PAINTSTRUCT ps; char szBuf[32] = "猫でもわかるLayer"; BITMAP bmp_info; HBITMAP hBmp; int wx, wy; static int nAlpha = 0; static BOOL bInc = TRUE; switch (msg) { case WM_CREATE: SetTimer(hWnd, ID_MYTIMER, 100, NULL); SetLayeredWindowAttributes(hWnd, 0, 0, LWA_ALPHA); break; case WM_TIMER: if (wp != ID_MYTIMER) { return DefWindowProc(hWnd, msg, wp, lp); } if (bInc) { nAlpha += 20; if (nAlpha >= 255) { nAlpha = 255; KillTimer(hWnd, ID_MYTIMER); } } else { nAlpha -= 20; if (nAlpha <= 0) { nAlpha = 0; KillTimer(hWnd, ID_MYTIMER); DestroyWindow(hWnd); } } SetLayeredWindowAttributes(hWnd, 0, (BYTE)nAlpha, LWA_ALPHA); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); hBrush = CreateSolidBrush(RGB(255, 0, 0)); SelectObject(hdc, hBrush); ExtFloodFill(hdc, 1, 1, RGB(255, 255, 255), FLOODFILLSURFACE); hBmp = (HBITMAP)LoadImage(hInst, "MYBMP",IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); GetObject(hBmp, (int)sizeof(BITMAP), &bmp_info); wx = bmp_info.bmWidth; wy = bmp_info.bmHeight; hdc_mem = CreateCompatibleDC(hdc); SelectObject(hdc_mem, hBmp); BitBlt(hdc, 0, 0, wx, wy, hdc_mem, 0, 0, SRCCOPY); DeleteObject(hBmp); DeleteDC(hdc_mem); SetBkMode(hdc, TRANSPARENT); TextOut(hdc, 10, 90, szBuf, (int)strlen(szBuf)); DeleteObject(hBrush); EndPaint(hWnd, &ps); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよろしいですか", "確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { SetTimer(hWnd, ID_MYTIMER, 100, NULL); bInc = FALSE; } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }最初に説明したとおりです。
さて、ここでWM_TIMERメッセージが来るたびに
SetLayeredWindowAttributes(hWnd, 0, (BYTE)nAlpha, LWA_ALPHA);
を実行していますが3番目の引数nAlphaはBYTEに型キャストして使っています。 それなら初めからBYTE型で宣言しておけばよいじゃないか、と思われるかもしれません。
すると、次のような不具合が発生します。
この変数に250が格納されているとき、nAlpha += 20;が実行されると 桁あふれを起こしてしまい、if (nAlpha >= 255)の条件に引っかからなくなってしまいます。 実験するとわかりますが、ウィンドウがかなり濃くなったと思ったら、また薄くなる、という 動作を繰り返すことになります。
さて、今回のプログラムと同様の動作はAnimateWindow関数を使って実現することも可能です。 いろいろ研究してみてください。
Update 27/Apr/2003 By Y.Kumei