X-Window の Enlightenment などでは 、背景が透けて見える半透明ウィンドウを表示することが出来ます。こういう 半透明ウィンドウを Windows でも作れるのでしょうか?
最初は背景色を NULL_BRUSH にして、いろいろ処理をしてやれば簡単に 出来るだろうと軽く考えてましたが、NULL_BRUSH を使っても背景は 透明にはなりませんでした。NULL_BRUSH は背景を 透明にするのではなくて「再描画しないこと」を指定するものなので当然ですね。 これと同じ理由でウィンドウスタイルに WS_EX_TRANSPARENT を指定しても 駄目でした。
で、次に考えたのが SetWindowRgn を使ってみる事ですが、 SetWindowRgn はウィンドウの透明化をする事は出来ても半透明化 をする事は出来ません。しかも透明化した部分には字や絵を描画することが 出来ません。
とりあえず描画はおいといて、半透明化を先に考えてみることにしました。 SetWindowRgn を使う限りでは前にやった様な 計算による半透明化処理 を行うことは不可能です。となると、残された 方法はメッシュ半透明、俗に言う「セガサターン方式(^^;半透明」を使うことでした。
詳しくはソースをみてもらうことにして、原理としてはただメッシュ状のリージョン を作って SetWindowRgn するだけです。これで次の様な半透明 ウィンドウが出来ました。
こうして、とりあえず(偽)半透明ウィンドウは出来ました。が、今度は描画に関する 問題が生じました。つまり、このウィンドウ上で文字や絵を描くと、 メッシュ状のリージョンを指定しているため穴だらけの画像になってしまいます(^^; さらに SetWindowRgn の宿命として「死ぬほど重い、て言うか、実際死ぬ」 という問題もあります (^^; これらの問題は SetWindowRgn を使っている限り解決しませんね (-_-;
と言う訳で
「現在の Windows では半透明ウィンドウを作成するのは極めて困難」
という結論に至りました(← 駄目じゃん (^^;; )
ところで Windows 2000 の GDI+ ならば半透明処理の専用 API がある(らしい)ので 半透明のウィンドウスタイルも出来るんじゃないでしょうか。 とりあえず完全な半透明ウィンドウの実現は Windows 2000 待ちでしょうね。 もし上の方法以外で半透明処理をする方法を 知ってる方がいらっしゃいましたら是非教えて下さい。 ちなみにカレンダーとかテキストビュアー とかで「半透明」をうたっているものがありますが、あれはウィンドウを表示 する前にバックの画面をキャプチャーしているだけなので本当の半透明 ウィンドウではありません。実際、後ろのウインドウ内でアニメーション をさせたりするとそれが全く反映されませんし。
それと最後に注意なのですが、sp2 以前の NT4 の場合 BeginPath() を使うと OS 自体がクラッシュする事があるそうなので(おいおい(^^;) 下のプログラムは動かさないで下さい。
// 半透明ウィンドウ 99/3/4 // (c) tokai@fides.dti.ne.jp #include < windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); char szClassName[] = "TOMEIWIN"; // メイン int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPreInst, LPSTR lpszCmdLine, int nCmdShow) { HWND hWnd; MSG lpMsg; WNDCLASS wndClass; // ウィンドウ登録 if (!hPreInst) { wndClass.style = 0; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInst; wndClass.hIcon = NULL; wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = szClassName; if (!RegisterClass(&wndClass)) return FALSE; } // ウィンドウ作成 hWnd = CreateWindow( szClassName,"半透明", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, CW_USEDEFAULT,CW_USEDEFAULT, 300,200,NULL,NULL,hInst,NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // メッセージループ while (GetMessage(&lpMsg, NULL, 0, 0)) { TranslateMessage(&lpMsg); DispatchMessage(&lpMsg); } return (lpMsg.wParam); } // プロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { static HRGN hRgn; HRGN hRgn2,hRgn3; HDC hDC; RECT rt; HPEN hPen,hOldPen; HBRUSH hBrush,hOldBrush; static HDC hBufDC; static HBITMAP hBufBit; LONG width,height,cWidth,cHeight,frameWidth,captionHeight; POINT point[5]; INT nPoints; INT i; switch (msg) { case WM_CREATE: // 初期化 // ウィンドウサイズ取得 GetWindowRect(hWnd,&rt); width = rt.right-rt.left; height = rt.bottom-rt.top; // クライアント領域サイズ取得 GetClientRect(hWnd,&rt); cWidth = rt.right-rt.left; cHeight = rt.bottom-rt.top; // キャプションの高さと枠の幅 captionHeight = GetSystemMetrics(SM_CYCAPTION) +GetSystemMetrics(SM_CYFIXEDFRAME); frameWidth = GetSystemMetrics(SM_CXFIXEDFRAME); // 裏画面の作成 hDC = GetDC(hWnd); hBufBit = CreateCompatibleBitmap(hDC,width,height); hBufDC = CreateCompatibleDC(hDC); SelectObject(hBufDC,hBufBit); ReleaseDC(hWnd,hDC); // メッシュリージョンの作成 if(BeginPath(hBufDC)){ for(i=-cHeight;i < width;i+=2){ point[0].x = i; point[0].y = captionHeight; point[1].x = i+cHeight; point[1].y = captionHeight+cHeight; point[2].x = i+cHeight+1; point[2].y = captionHeight+cHeight; point[3].x = i+1; point[3].y = captionHeight; point[4].x = i; point[4].y = captionHeight; nPoints = 5; PolyPolygon(hBufDC,point,&nPoints,1); } if(EndPath(hBufDC)) hRgn = PathToRegion(hBufDC); } // 枠のリージョン作成 hRgn2 = CreateRectRgn(0,0,width,height); hRgn3 = CreateRectRgn(frameWidth,captionHeight, frameWidth+cWidth,captionHeight+cHeight); CombineRgn(hRgn2,hRgn2,hRgn3,RGN_DIFF); // 合成してリージョン設定 CombineRgn(hRgn,hRgn,hRgn2,RGN_OR); SetWindowRgn(hWnd,hRgn,TRUE); DeleteObject(hRgn2); DeleteObject(hRgn3); // 背景塗りつぶし hPen = CreatePen(PS_SOLID,1,RGB(255,0,0)); hBrush = CreateSolidBrush(RGB(255,0,0)); hOldPen = (HPEN)SelectObject(hBufDC,hPen); hOldBrush = (HBRUSH)SelectObject(hBufDC,hBrush); Rectangle(hBufDC,-1,-1,cWidth,cHeight); SelectObject(hBufDC,hOldPen); SelectObject(hBufDC,hOldBrush); DeleteObject(hPen); DeleteObject(hBrush); break; case WM_PAINT: // 描画(再描画のみ) PAINTSTRUCT ps; hDC = BeginPaint(hWnd,&ps); BitBlt(hDC,ps.rcPaint.left,ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left,ps.rcPaint.bottom-ps.rcPaint.top, hBufDC,ps.rcPaint.left,ps.rcPaint.top,SRCCOPY); ReleaseDC(hWnd,hDC); break; case WM_CLOSE: // クローズ // 裏画面削除 DeleteDC(hBufDC); DeleteObject(hBufBit); // リージョン削除 SetWindowRgn(hWnd,NULL,TRUE); DeleteObject(hRgn); DestroyWindow(hWnd); break; case WM_DESTROY: // デストロイ PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, msg, wp, lp)); } return (0L); } //EOF