第117章 分割ウィンドウもどきを作る その1


今回は、ウィンドウが上下または、左右に分割して それぞれに別々の内容を表示する方法を考えます。 じつは、MFCでは比較的簡単に実現できるのですが SDKレベルではなかなか難しいものがあります。 (筆者が知らないだけかもしれません) そこで、もっと簡易な(安直な)方法で分割ウィンドウ もどきを作ってみます。一番簡単なのは 子供ウィンドウを作って、親のクライアントに貼り付ける というのが誰もが思いつく方法です。 親のサイズが変わったら子供も矛盾のないように サイズを変更します。



一つのウィンドウがあたかも真ん中の境界線で 分割しているかのように見えます。



境界線をドラッグすると左右の領域の大きさを変えることができます。



実は右半分はエジットコントロールなのです。左半分は 親のクライアント領域です。両方ともコントロールなり、 子供ウィンドうなりを貼ればよかったのですがプログラムの 簡略化のためにこのようにしてみました。真ん中の境界線は エジットコントロールの枠なのです。また、左右と下の 境界線は親ウィンドウのものです。 (エジットコントロールの上・右・下の境界線は親ウィンドウから はみ出しているため見えない)

何か、インチキ臭いプログラムですが中身を見てみましょう。

// split01.cpp #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); char szClassNme[] = "split01"; HINSTANCE hInst; int w1x, w1y, w2x, w2h; void GetWinRect(HWND, int *, int *); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpszCmdLine, int nCmdShow) { HWND hWnd; MSG lpMsg; WNDCLASSEX myProg; hInst = hInstance; myProg.cbSize = sizeof(WNDCLASSEX); myProg.style = CS_HREDRAW | CS_VREDRAW; myProg.lpfnWndProc = WndProc; myProg.cbClsExtra = 0; myProg.cbWndExtra = 0; myProg.hInstance = hInstance; myProg.hIcon = LoadIcon(NULL, IDI_APPLICATION); myProg.hCursor = LoadCursor(NULL, IDC_ARROW); myProg.hbrBackground = GetStockObject(WHITE_BRUSH); myProg.lpszMenuName = NULL; myProg.lpszClassName = szClassNme; myProg.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&myProg)) return FALSE; hWnd = CreateWindow(szClassNme, "猫でもわかるプログラミング", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, 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 wParam, LPARAM lParam) { int id; static HWND hEdit; static int wx, wy, wsx, wsy;//クライアント領域の幅、高さ HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_CREATE: GetWinRect(hWnd, &wx, &wy); hEdit = CreateWindow( "EDIT", "ウィンドウ2です", WS_CHILD | WS_THICKFRAME | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 300, -3, wx-300+3, wy+6, hWnd, (HMENU)100, hInst, NULL); break; case WM_SIZE: GetWinRect(hWnd, &wx, &wy); GetWinRect(hEdit, &wsx, &wsy); if (wsx > wx) wsx = wx; if (wsx < 3) wsx = 3; MoveWindow(hEdit, wx-wsx, -3, wsx+3, wy+6, TRUE); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 0, 0, "ウィンドウ1です", 16); EndPaint(hWnd, &ps); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, msg, wParam, lParam)); } return 0; }

親が作られたらすぐに、エジットコントロールを作ります。 このとき、ウィンドウスタイルにWS_THICKFRAMEを加えないと サイズ変更の可能なウィンドウ枠が作られないので注意してください。 また、左上の座標を(300, 0)にせず(300, -3)にしている点に 注意してください。(わずかに上方向に枠の太さ分ずらしています) 枠の太さはGetSystemMetrics関数で求めることができますが 手抜きで適当な値にしておきました。

親ウィンドウのサイズが変化したら(WM_SIZE)エジットコントロールの 大きさも変更しています。この時まず親とエジットコントロールの 大きさを調べておきます。そして、エジットコントロールの サイズを変更しています。この場合サイズ変更のウィンドウは 1つだけなので簡単のためにMoveWindow関数を利用しています。 2つ以上のウィンドウを変更するときは違う関数があります。 必要が生じたら解説します。

void GetWinRect(HWND hWnd, int *x, int *y) { RECT rc; GetClientRect(hWnd, &rc); *x = rc.right - rc.left; *y = rc.bottom - rc.top; return; }

ウィンドウのクライアント領域のサイズを調べる関数を 自作してみました。(あまり意味はありませんが・・)

今回のプログラムは実際に自分でいろいろ動かしてみると 不備な点がたくさんあります。改良してみてください。 そして、左半分にも子供ウィンドウを貼り付けたものにも 挑戦してみてください。この時どちらかの子供ウィンドウを 枠なしにしておくとよいです。


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

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