今回はエディットを分割します。2つのウインドウの境界をマウスでドラッグすることにより、ウインドウのサイズを変えることができるようにします。
2つのウインドウの境界の幅は、4ptとします。この境界上にマウスポインタを持ってくると、マウスポインタが変わるようにします。
WindowsSDKで分割ウインドウを作成するのは難しく、工夫が要ります。(MFCなら簡単なのですが。)
2つのウインドウを作成し、そのうちひとつのウインドウのスタイルに、WS_THICKFRAME(サイズ変更の可能なウィンドウ枠)を指定する方法もありますが、今回はマウスキャプチャを使う方法を用います。
今回のアプリケーションの欠点は次のとおりです。
・ウインドウのサイズを変えるとき、InvalidateRect()が常時発生するため、画面がちらつき、CPUの消費が大きい。
エディット - インコのWindowsSDK で作成したソースを修正します。
流れ
WM_CREATE
1.2つのエディトコントロールを作成します。
WM_SIZE
1.MoveWindow()で、エディットのウインドウサイズを変えます。
2.InvalidateRect()で、再描画します。
WM_LBUTTONDOWN
マウスの左ボタンが押されたとき、WM_LBUTTONDOWNメッセージが発生します。
1.SetCapture()でマウスキャプチャを開始。
これがないと、ウインドウの境界をマウスで一気に動かすと、ウインドウの境界が動かなくなります。
2.マウスカーソルを、左右両方向矢印カーソル(IDC_SIZEWE)に変えます。
これがないと、マウスの左ボタンを押した直後のマウスポインタが、標準のマウスポインタに変わってしまいます。
WM_LBUTTONUP
マウスの左ボタンを離したとき、WM_LBUTTONUPメッセージが発生します。
1.GetWindowRect()で親ウインドウのウインドウサイズを取得し、RECT構造体にセットします。
BOOL GetWindowRect( HWND hWnd, // ウィンドウハンドル PRECT pRect // RECT構造体 );
2.ReleaseCapture()でマウスキャプチャを終了。
3.PostMessage()で親ウインドウにWM_SIZEメッセージを発生させ、ウインドウを再描画します。
BOOL PostMessage( HWND hWnd, // ウィンドウハンドル UINT Msg, // メッセージコード WPARAM wParam, // wParamパラメータ LPARAM lParam // lParamパラメータ );
WM_MOUSEMOVE
マウスカーソルが移動したとき、WM_MOUSEMOVEメッセージが発生します。
●マウスをドラッグ中のとき、
1.GetWindowRect()で親ウインドウのウインドウサイズを取得し、RECT構造体にセットします。
2.PostMessage()で親ウインドウにWM_SIZEメッセージを発生させ、ウインドウを再描画します。
●マウスをドラッグ中でないとき、
3.2つのエディトコントロールに挟まれた隙間に、マウスカーソルがある場合、マウスカーソルを、左右両方向矢印カーソル(IDC_SIZEWE)に変えます。
それ以外の場合は、通常のマウスカーソルにします。
ソースコードの入力
ソースコードは下記のように入れてください。
#include <windows.h> #include "resource.h" #define SPLIT_WIDTH 2 #define SPLIT_MIN 50 // グローバル変数: HINSTANCE hInst; // 現在のインターフェイス int width = 100; // 分割ウインドウ(左)の幅 // このコード モジュールに含まれる関数の宣言を転送します: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int MaxMinPoint(LPARAM, RECT); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; MyRegisterClass(hInstance); // アプリケーションの初期化を実行します: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } // メイン メッセージ ループ: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; } // // 関数: MyRegisterClass() // // 目的: ウィンドウ クラスを登録します。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL , IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_HP); wcex.lpszClassName = TEXT("HP"); wcex.hIconSm = LoadIcon(NULL , IDI_APPLICATION); return RegisterClassEx(&wcex); } // // 関数: InitInstance(HINSTANCE, int) // // 目的: メイン ウィンドウを作成します。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // グローバル変数にインスタンス処理を格納します。 hWnd = CreateWindow(TEXT("HP"), TEXT("HP"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // 関数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: メイン ウィンドウのメッセージを処理します。 // // WM_CREATE - ウインドウ作成時の処理 // WM_SIZE - ウインドウサイズ変更時の処理 // WM_COMMAND - アプリケーション メニューの処理 // WM_DESTROY - 中止メッセージを表示して戻る // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; HWND static hEdit1; HWND static hEdit2; RECT rc; static BOOL push = FALSE; switch (message) { case WM_CREATE: hEdit1 = CreateWindowEx(WS_EX_CLIENTEDGE, // 拡張ウィンドウスタイル TEXT("EDIT"), TEXT("ここに入力"), WS_CHILD | WS_VISIBLE | ES_MULTILINE, 0, 0, 0, 0, hWnd, (HMENU)IDC_EDIT1, hInst, NULL); hEdit2 = CreateWindowEx(WS_EX_CLIENTEDGE, // 拡張ウィンドウスタイル TEXT("EDIT"), TEXT("ここに入力"), WS_CHILD | WS_VISIBLE | ES_MULTILINE, 0, 0, 0, 0, hWnd, (HMENU)IDC_EDIT2, hInst, NULL); break; case WM_SIZE: MoveWindow(hEdit1, 0, 0, width - SPLIT_WIDTH, HIWORD(lParam), TRUE); MoveWindow(hEdit2, width + SPLIT_WIDTH, 0, LOWORD(lParam), HIWORD(lParam), TRUE); InvalidateRect(hEdit1, NULL, TRUE); InvalidateRect(hEdit2, NULL, TRUE); break; case WM_LBUTTONDOWN: // マウスの左ボタンが押されたとき // マウスキャプチャを開始する SetCapture(hWnd); SetCursor(LoadCursor(NULL, IDC_SIZEWE)); push = TRUE; // 左ボタンが押された break; case WM_LBUTTONUP: // マウスの左ボタンが離されたとき GetWindowRect(hWnd, &rc); // マウスカーソルの位置を取得して、終点として保存しておく width = MaxMinPoint(lParam, rc); push = FALSE; // 左ボタンが押されてない // マウスキャプチャを終了する ReleaseCapture(); PostMessage(hWnd, WM_SIZE, SIZE_RESTORED, ((rc.bottom-rc.top)<<16) | (rc.right-rc.left)); break; case WM_MOUSEMOVE: // マウスカーソルが移動したとき if(push == TRUE) { GetWindowRect(hWnd, &rc); // マウスカーソルの位置を取得して、終点として保存しておく width = MaxMinPoint(lParam, rc); PostMessage(hWnd, WM_SIZE, SIZE_RESTORED, ((rc.bottom-rc.top)<<16) | (rc.right-rc.left)); } else if((width <= (LOWORD(lParam) + SPLIT_WIDTH)) && (width >= (LOWORD(lParam) - SPLIT_WIDTH))) { SetCursor(LoadCursor(NULL, IDC_SIZEWE)); } else { SetCursor(LoadCursor(NULL, IDC_ARROW)); } break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 選択されたメニューの解析: switch (wmId) { case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int MaxMinPoint(LPARAM lParam,RECT rc) { POINTS pts; pts = MAKEPOINTS(lParam); width = pts.x; if(width < SPLIT_MIN) { width = SPLIT_MIN; } else if(width > (rc.right - rc.left - SPLIT_MIN -10)) { width = rc.right - rc.left - SPLIT_MIN -10; } else { ; } return width; }
上記の太線で示している箇所のみ追加です。
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDC_HP 109
#define IDC_EDIT1 1001
#define IDC_EDIT2 1002
上記の太線で示している箇所のみ追加です。
#include "resource.h" ///////////////////////////////////////////////////////////////////////////// // // メニュー // IDC_HP MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "アプリケーションの終了(&X)", IDM_EXIT END POPUP "ヘルプ(&H)" BEGIN MENUITEM "バージョン情報(&A)...", IDM_ABOUT END END