第125章 丸いウィンドウを作る


Windows95が出た当時、シェアウェアで丸いウィンドウの時計 が出て話題になったことがあります。これは、単に丸いグラフィックスの 外側のウィンドウを透明にしただけではありません。 それが証拠には円の下45度方向で円のすぐ外側にある 他のウィンドウをクリックすることができることでもわかります。 今回は、手始めに丸いウィンドウに猫のグラフィックスを表示してみます。



おー!!丸いウィンドウだ!

しかも、右下にあるヘルプファイルをクリックして起動させることもできます。 当然丸いウィンドウにはタイトルバーなどを付けることはできません。 ウィンドウの移動とか、メニューを出すにはそれなりに工夫することが必要です。

ウィンドウの移動はプログラムを簡単にするため次のようにしました。 クライアント領域を左クリックすると、カーソルが黄色い丸に変わります。 そのまま移動したいところまでドラッグすると丸いカーソルだけが動いていきます。 マウスを放すとウィンドウ本体が移動します。

また、プログラムを終了したいときは右クリックをします。

左のようなビットマップを作ります。これをコピーしてリソースエジタに 貼り付けます。ビットマップリソースの名前は"MYBMP"にしておきます。



左のようなカーソルを作ります。("MYCURSOR")VC++の リソースエジタでカラーのカーソルがうまく作れないときは 白黒にするか、 リソースキットなどについているエジタを使います。 緑色の部分は実際には透明になります。 また、カーソルのホットスポットをカーソルの中央部にしておくと カーソルが切り替わるとき違和感がありません。

// round01.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Bitmap // MYBMP BITMAP DISCARDABLE "my44.bmp" ///////////////////////////////////////////////////////////////////////////// // // Cursor // MYCURSOR CURSOR DISCARDABLE "mycursor.cur"

ビットマップとカーソルのリソース・スクリプトです。

// round01.cpp #define STRICT #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "round01"; //ウィンドウクラス int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

これは、いつもと同じです。

//ウィンドウ・クラスの登録 BOOL 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 = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); }

ここもいつもと同じです。

//ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかる丸いウィンドウ",//タイトルバーはなくても名前は付けておく WS_POPUP, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 150,//幅 150,//高さ NULL,//親ウィンドウのハンドル、親を作るときはNULL NULL,//メニューハンドル、クラスメニューを使うときはNULL hInst,//インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

いつもと大体同じです。タイトルバーはありませんが一応名前を 付けておきます。起動時にこの名前がタスクバーに表示されます。

ウィンドウスタイルはWS_POPUPにします。また、ウィンドウの大きさは 150*150にしておきます。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HRGN hRound; HBITMAP hBitmap; BITMAP bmp_info; HDC hdc, hdc_mem; PAINTSTRUCT ps; static HINSTANCE hInst; int wx, wy, x, y; POINT pt; LPCREATESTRUCT pCS; switch (msg) { case WM_CREATE: pCS = (LPCREATESTRUCT)lp; hInst = pCS->hInstance; hRound = CreateEllipticRgn(0, 0, 150, 150); SetWindowRgn(hWnd, hRound, TRUE); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); hBitmap = LoadBitmap(hInst, "MYBMP"); GetObject(hBitmap, sizeof(BITMAP), &bmp_info); wx = bmp_info.bmWidth; wy = bmp_info.bmHeight; hdc_mem = CreateCompatibleDC(hdc); SelectObject(hdc_mem, hBitmap); StretchBlt(hdc, 0, 0, 150, 150, hdc_mem, 0, 0, wx, wy, SRCCOPY); DeleteDC(hdc_mem); DeleteObject(hBitmap); EndPaint(hWnd, &ps); break; case WM_LBUTTONDOWN: SetCursor(LoadCursor(hInst, "MYCURSOR")); SetCapture(hWnd); break; case WM_LBUTTONUP: x = LOWORD(lp); y = HIWORD(lp); pt.x = x; pt.y = y; ClientToScreen(hWnd, &pt); MoveWindow(hWnd, pt.x-75, pt.y-75, 150, 150, TRUE); SetCursor(LoadCursor(NULL, IDC_ARROW)); ReleaseCapture(); break; case WM_RBUTTONDOWN: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: DeleteObject(hRound); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }

さて、ここが一番肝心なところですが、ウィンドウができたらすぐに SetWindowRgn関数でウィンドウを変形させます。

int SetWindowRgn( HWND hWnd, // ウィンドウハンドル HRGN hRgn, // リージョンのハンドル BOOL bRedraw // 再描画フラグ );

hWndは変形させたいウィンドウのハンドルを指定します。

hRgnは変形する形をリージョンで指定します。 リージョンについては第48章を 参照してください。

bRedrawはウィンドウリージョンが設定された後ウィンドウを 再描画するかどうかを指定します。

成功したときは0以外を返します。失敗したときは0を返します。

この関数を使えばウィンドウをいろいろに変形させることができます。

WM_PAINTメッセージが来たらウィンドウにビットマップを 表示させます。ビットマップの表示については 第26章を参照してください。

WM_LBUTTONDOWNが来たらカーソルを"MYCURSOR"に変えます。 そして、マウスキャプチャーを開始します。マウスキャプチャーに関しては 第101章を参照してください。

WM_LBUTTONUPが来たらその時のマウスの位置(クライアント座標)を取得します。 そして、それをスクリーン座標に変換します。このへんのところは 第102章を参考にしてください。

マウスのスクリーン座標がわかったら、ウィンドウの中央部が その座標になるようにMoveWindow関数でウィンドウを移動させます。

WM_RBUTTONDOWNがきたら、WM_CLOSEメッセージを送ってアプリケーションを終了させます。 ここで、ボップアップメニューなどを表示してもよいですね。 ポップアップメニューに関しては第44章を 参照してください。

WM_DESTROYメッセージのところでリージョンを削除しておきます。

変形ウィンドウは工夫次第でいろいろおもしろいことができそうです。 (ただ、あまり実用的なプログラムではないですね・・・)


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 19/May/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。