STATICコントロールのリサイズ
- 分割ウィンドウの表示例
- 今遊んでいるダイアログ
CreateWindowでウィンドウを生成するときにスタイルでWS_SIZEBOXを指定すればリサイズできる枠がつきます。その枠をドラッグしたりすると通常、ウィンドウのサイズが変更されます。ところが、STATICコントロールではできませんでした。
どうやらスタティックコントロールは外枠、即ちクライアントの外をクリックした際に生じるメッセージWM_NCHITTESTに対し、HTTRANSPARENTを返すみたいです。これでは何も動作しません。そこで、これらのメッセージの処理をDefWindowProcに任せました。
これでもリサイズはできません。というわけで、強引に全てをDefWindowProcに任せ、スタティックコントロールとして使うメッセージだけを元のスタティックコントロールのプロシージャに任せることにしました。
- divided_window.h
#pragma once #include <Windows.h> class DividedWindows { public: DividedWindows(HWND h_wnd); ~DividedWindows(); static void Register(); void show(); private: static LRESULT CALLBACK WindowProc(HWND h_wnd, UINT message, WPARAM wp, LPARAM lp); static LRESULT CALLBACK Child1Proc(HWND h_wnd, UINT message, WPARAM wp, LPARAM lp); void onCreate(); void onLButtonUp(); LRESULT mainProc(HWND h_wnd, UINT message, WPARAM wp, LPARAM lp); SHORT x, y; SHORT width, height; SHORT rx, ry, lx, ly; SHORT r_width, l_width; SHORT r_height, l_height; HWND h_wnd; HWND h_child1; HWND h_child2; WNDPROC child1_proc; };
- divided_windows.cpp
#include "divided_windows.h" #include "resource.h" #include "project.h" #include <exception> DividedWindows::DividedWindows(HWND h_wnd) { x = y = 0; width = height = 200; CreateWindow( L"DividedWindows", L"title", WS_OVERLAPPEDWINDOW | WS_CHILD | WS_CLIPCHILDREN, x, y, width, height, h_wnd, NULL, GetModuleHandle(NULL), this); // ここに来るのはWM_CREATEメッセージの処理の後 if(this->h_wnd == NULL) { throw std::exception(); } } void DividedWindows::show() { ShowWindow(h_wnd, SW_SHOW); } void DividedWindows::Register() { WNDCLASS wndc; wndc.style = CS_HREDRAW | CS_VREDRAW; wndc.lpfnWndProc = WindowProc; wndc.cbClsExtra = wndc.cbWndExtra = 0; wndc.hInstance = NULL; wndc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndc.hCursor = LoadCursor(NULL, IDC_ARROW); wndc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndc.lpszMenuName = NULL; wndc.lpszClassName = L"DividedWindows"; if(!RegisterClass(&wndc)) { throw std::exception(); } } LRESULT CALLBACK DividedWindows::WindowProc(HWND h_wnd, UINT message, WPARAM wp, LPARAM lp) { DividedWindows* self = (DividedWindows*)GetWindowLongPtr(h_wnd, GWLP_USERDATA); if(self == NULL) { if(message == WM_CREATE) { self = (DividedWindows*)((LPCREATESTRUCT)lp)->lpCreateParams; SetWindowLongPtr(h_wnd, GWLP_USERDATA, (LPARAM)self); self->h_wnd = h_wnd; self->onCreate(); } return DefWindowProc(h_wnd, message, wp, lp); } else { return self->mainProc(h_wnd, message, wp, lp); } } LRESULT DividedWindows::mainProc(HWND h_wnd, UINT message, WPARAM wp, LPARAM lp) { switch(message) { case WM_LBUTTONUP: onLButtonUp(); break; case WM_SIZE: SCOPE { int frame_size = GetSystemMetrics(SM_CXSIZEFRAME) * 2; RECT rc; GetClientRect(h_wnd, &rc); r_width = rc.right - l_width + frame_size + 2; r_height = rc.bottom + 2; l_height = rc.bottom + frame_size * 2 + 2; lx = -frame_size - 1; ly = -frame_size - 1; rx = l_width - frame_size - 1; ry = -1; MoveWindow(h_child1, lx, ly, l_width, l_height, TRUE); MoveWindow(h_child2, rx, ry, r_width, r_height, TRUE); } break; } return DefWindowProc(h_wnd, message, wp, lp); } DividedWindows::~DividedWindows() { DestroyWindow(h_wnd); } void DividedWindows::onCreate() { int frame_size = GetSystemMetrics(SM_CXSIZEFRAME) * 2; RECT rc; GetClientRect(h_wnd, &rc); l_width = rc.right / 2; l_height = rc.bottom + frame_size * 2; h_child1 = CreateWindowEx(WS_EX_CLIENTEDGE, L"STATIC", L"static1", WS_CHILD | WS_VISIBLE | WS_SIZEBOX, 0, 0, 0, 0, h_wnd, NULL, GetModuleHandle(NULL), this); h_child2 = CreateWindow( L"STATIC", L"static2", WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY, 0, 0, 0, 0, h_wnd, NULL, GetModuleHandle(NULL), this); //h_child1のウィンドウプロシージャを取得 SetWindowLongPtr(h_child1, GWLP_USERDATA, (LONG_PTR)this); child1_proc = (WNDPROC)GetWindowLongPtr(h_child1, GWLP_WNDPROC); SetWindowLongPtr(h_child1, GWLP_WNDPROC, (LONG_PTR)Child1Proc); } void DividedWindows::onLButtonUp() { HDC hdc; hdc = GetDC(h_child1); TextOut(hdc, 10, 10, L"TESTA", lstrlen(L"TESTA")); ReleaseDC(h_child1, hdc); hdc = GetDC(h_child2); TextOut(hdc, 10, 10, L"TESTB", lstrlen(L"TESTB")); ReleaseDC(h_child2, hdc); } LRESULT CALLBACK DividedWindows::Child1Proc(HWND h_wnd, UINT message, WPARAM wp, LPARAM lp) { DividedWindows* self = (DividedWindows*)GetWindowLongPtr(h_wnd, GWLP_USERDATA); assert(self != NULL); if(self != NULL) { switch(message) { case WM_SIZE: SCOPE { RECT rc; GetWindowRect(h_wnd, &rc); self->l_width = rc.right - rc.left; InvalidateRect(h_wnd, NULL, TRUE); SendMessage(self->h_wnd, WM_SIZE, 0, 0); } break; case WM_PAINT: return CallWindowProc(self->child1_proc, h_wnd, message, wp, lp); } return DefWindowProc(h_wnd, message, wp, lp); } }
サブクラス化したChild1Procの処理でほとんど全ての処理をreturn DefWindowProc(h_wnd, message, wp, lp);としてデフォルト動作させているところがポイントです。スタティックコントロールの詳細の動作については、Win32API-スタティック コントロールの概要が大変参考になります。