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