ヘッダコントロールのセパレータをドラッグするとそれに合わせて、リストビューの
アイテムの幅も変化します。
作り方は、だいたい想像がつくと思います。ヘッダーコントロールの通知メッセージを
捕まえれば良いですね。前章でやったHDN_ENDTRACK通知メッセージを捕まえます。
では、プログラムを見てみましょう。
メニューのリソース・スクリプトの一部です。// header02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END END
コモンコントロールの前準備を忘れないでください。(commctrl.hのインクルード、 comctl32.libのリンク)// header02.cpp #ifndef STRICT #define STRICT #endif #define ID_HEADER 100 #define ID_LIST 101 #include <windows.h> #include <commctrl.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MySetItem(HWND); BOOL MySetListItem(HWND); char szClassName[] = "header02"; //ウィンドウクラス HINSTANCE hInst;
このへんは、いつも通りです。int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM 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 = "MYMENU"; //メニュー名 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_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
メインウィンドウ(親ウィンドウ)のプロシージャです。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, nHeaderh; static HWND hHeader, hList; INITCOMMONCONTROLSEX ic; RECT rc; HDLAYOUT hdl; WINDOWPOS wpos; NMHDR *lpnmhdr; NMHEADER *lpnh; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&ic); hHeader = CreateWindow(WC_HEADER, "", WS_CHILD | WS_BORDER | HDS_BUTTONS, 0, 0, 0, 0, hWnd, (HMENU)ID_HEADER, hInst, NULL); hList = CreateWindow(WC_LISTVIEW, "", WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_NOCOLUMNHEADER, 0, 0, 0, 0, hWnd, (HMENU)ID_LIST, hInst, NULL); MySetItem(hHeader); MySetListItem(hList); break; case WM_SIZE: rc.left = 0; rc.top = 0; rc.right = LOWORD(lp); rc.bottom = HIWORD(lp); hdl.pwpos = &wpos; hdl.prc = &rc; SendMessage(hHeader, HDM_LAYOUT, 0, (LPARAM)&hdl); SetWindowPos(hHeader, wpos.hwndInsertAfter, wpos.x, wpos.y, wpos.cx, wpos.cy, wpos.flags | SWP_SHOWWINDOW); GetWindowRect(hHeader, &rc); nHeaderh = rc.bottom - rc.top; MoveWindow(hList, 0, nHeaderh, LOWORD(lp), HIWORD(lp) - nHeaderh, TRUE); break; case WM_NOTIFY: lpnmhdr = (NMHDR *)lp; if (lpnmhdr->hwndFrom != hHeader) return (DefWindowProc(hWnd, msg, wp, lp)); switch (lpnmhdr->code) { case HDN_ENDTRACK: lpnh = (NMHEADER *)lp; ListView_SetColumnWidth(hList, lpnh->iItem, lpnh->pitem->cxy); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hList); DestroyWindow(hHeader); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
WM_CREATEメッセージが来たら、ヘッダーコントロールとリストビューを 作ります。リストビューは親の子供として作りました。 また、リストビューではカラムヘッダは必要ないので、LVS_NOCOLUMNHEADERスタイルを 加えておきます。
WM_SIZEメッセージが来たら、ヘッダーコントロールにHDM_LAYOUTメッセージを 送り、望ましい大きさに調整します。 次にヘッダーコントロールの高さを求めて、リストビューの位置と大きさを 調整します。
WM_NOTIFYメッセージが来たら、どこのコントロールから来たかを調べ ヘッダーコントロール以外ものであれば、DefWindowProc関数に任せます。
通知メッセージがHDN_ENDTRACKであれば、リストビューのカラムの幅を調整します。
それ以外の通知メッセージはDefWindowProc関数に任せます。
プログラム終了時に、リストビュー、ヘッダーコントロールを破棄します。
ヘッダーコントロールにアイテムを挿入します。BOOL MySetItem(HWND hHeader) { HDITEM hi; hi.mask = HDI_FORMAT | HDI_TEXT | HDI_WIDTH; hi.pszText = "名 前"; hi.cxy = 100; hi.fmt = HDF_CENTER | HDF_STRING; hi.cchTextMax = strlen(hi.pszText); SendMessage(hHeader, HDM_INSERTITEM, 0, (LPARAM)&hi); hi.pszText = "住所"; hi.cxy = 200; hi.cchTextMax = strlen(hi.pszText); SendMessage(hHeader, HDM_INSERTITEM, 1, (LPARAM)&hi); return TRUE; }
リストビューにアイテムやサブアイテムを挿入します。BOOL MySetListItem(HWND hList) { LVCOLUMN lc; LVITEM li; lc.mask = LVCF_WIDTH | LVCF_SUBITEM; lc.cx = 100; lc.iSubItem = 0; ListView_InsertColumn(hList, 0, &lc); lc.cx = 200; lc.iSubItem = 1; ListView_InsertColumn(hList, 1, &lc); li.mask = LVIF_TEXT; li.pszText = "粂井康孝"; li.iItem = 0; li.iSubItem = 0; ListView_InsertItem(hList, &li); li.pszText = "旭川市"; li.iItem= 0; li.iSubItem = 1; ListView_SetItem(hList, &li); li.pszText = "佐藤孝夫"; li.iItem = 1; li.iSubItem = 0; ListView_InsertItem(hList, &li); li.pszText = "札幌市"; li.iItem = 1; li.iSubItem = 1; ListView_SetItem(hList, &li); li.pszText = "田中美子"; li.iItem = 1; li.iSubItem = 0; ListView_InsertItem(hList, &li); li.pszText = "東京都"; li.iItem = 1; li.iSubItem = 1; ListView_SetItem(hList, &li); return TRUE; }
ListView_InsertColumnマクロを実行するときにLVITEM構造体の fmt, pszTextメンバは必要ないことに注意してください。 (ヘッダーコントロールが表示してくれている)
また、この時cxメンバをヘッダーコントロールのアイテムの幅に 合わせておきます。
今回は簡単でした。ヘッダーコントロールをクリックしたとき リストビューのアイテムを昇順や降順に並び替えるようにプログラムを改良してみてください。
Update 16/Oct/2000 By Y.Kumei