では、どのように選択項目を取得すればよいのでしょうか。
チェックされているかどうかを調べるのはListView_GetCheckStateマクロを使います。
hwndLVはリストビューコントロールのハンドルです。BOOL ListView_GetCheckState( HWND hwndLV, UINT iIndex );
ListView_GetNextItemマクロもよく使いますが、これはすでに 第108章で出ています。
残念なことにこのマクロではflagsにLVNI_CHECKED というのはありません。 チェックされているかどうかはアイテムを順番に調べていく必要があります。 アイテムの数はListView_GetItemCountマクロで調べることができます。int ListView_GetNextItem( HWND hwnd, int iStart, UINT flags );
戻り値がアイテムの数となります。int ListView_GetItemCount( HWND hwnd );
アイテムからテキストを取得するにはListView_GetItemTextマクロもすでに 第110章で出てきました。
では、プログラムを見てみましょう。
前章のプログラムにメニューをつけてみました。// newlist2.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "データ(&D)" BEGIN MENUITEM "チェックされたデータ(&C)", IDM_CHECK MENUITEM "選択されたアイテム(&S)", IDM_SELECT END END
前章とほとんど同じですが、いくつかの自作関数が増えました。// newlist2.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <commctrl.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); HWND MakeMyList(HWND); void InsertMyColumn(HWND); void InsertMyItem(HWND); void CheckMySelect(HWND); void CheckMyCheck(HWND); char szClassName[] = "newlist2"; //ウィンドウクラス 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, "猫でもわかるListView", //タイトルバーにこの名前が表示されます 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; }
メニューでIDM_SELECT, IDM_CHECKを選択すると、選択されている項目とか チェックされている項目がメッセージボックスで表示されます。 ここでは、それぞれの目的を達成するための自作関数を呼んでいます。 SetFocus関数でリストビューにフォーカスを戻しておかないと 選択されている項目の色が見えずに、どれが選択されているのか わからなくなります。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; INITCOMMONCONTROLSEX ic; static HWND hList; RECT rc; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&ic); hList = MakeMyList(hWnd); InsertMyColumn(hList); InsertMyItem(hList); break; case WM_SIZE: GetClientRect(hWnd, &rc); MoveWindow(hList, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_SELECT: CheckMySelect(hList); SetFocus(hList); break; case IDM_CHECK: CheckMyCheck(hList); SetFocus(hList); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hList); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
この3つの関数は前章と全く同じです。HWND MakeMyList(HWND hWnd) { HWND hList; DWORD dwStyle; hList = CreateWindowEx(0, WC_LISTVIEW, "", WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, 0, 0, hWnd, (HMENU)100, hInst, NULL); dwStyle = ListView_GetExtendedListViewStyle(hList); dwStyle |= LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP; ListView_SetExtendedListViewStyle(hList, dwStyle); return hList; } void InsertMyColumn(HWND hList) { LV_COLUMN lvcol; lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvcol.fmt = LVCFMT_LEFT; lvcol.cx = 100; lvcol.pszText = "名前"; lvcol.iSubItem = 0; ListView_InsertColumn(hList, 0, &lvcol); lvcol.cx = 50; lvcol.pszText = "性別"; lvcol.iSubItem = 1; ListView_InsertColumn(hList, 1, &lvcol); lvcol.cx = 200; lvcol.pszText = "住所"; lvcol.iSubItem = 2; ListView_InsertColumn(hList, 2, &lvcol); return; } void InsertMyItem(HWND hList) { LV_ITEM item; memset(&item, 0, sizeof(LV_ITEM)); item.mask = LVIF_TEXT; item.pszText = "粂井康孝"; item.iItem = 0; item.iSubItem = 0; ListView_InsertItem(hList, &item); item.pszText = "男"; item.iSubItem = 1; ListView_SetItem(hList, &item); item.pszText = "北海道旭川市"; item.iSubItem = 2; ListView_SetItem(hList, &item); item.pszText = "粂井ひとみ"; item.iItem = 1; item.iSubItem = 0; ListView_InsertItem(hList, &item); item.pszText = "女"; item.iSubItem = 1; ListView_SetItem(hList, &item); item.pszText = "東京都特許許可局"; item.iSubItem = 2; ListView_SetItem(hList, &item); item.pszText = "粂井志麻"; item.iItem = 2; item.iSubItem = 0; ListView_InsertItem(hList, &item); item.pszText = "女"; item.iSubItem = 1; ListView_SetItem(hList, &item); item.pszText = "空知郡妹背牛町"; item.iSubItem = 2; ListView_SetItem(hList, &item); return; }
選択されている項目をメッセージボックスで表示する関数です。void CheckMySelect(HWND hList) { int nItem = -1; char str[256], name[64], sex[8], address[128]; while ((nItem = ListView_GetNextItem(hList, nItem, LVNI_SELECTED)) != -1) { ListView_GetItemText(hList, nItem, 0, name, sizeof(name)); ListView_GetItemText(hList, nItem, 1, sex, sizeof(sex)); ListView_GetItemText(hList, nItem, 2, address, sizeof(address)); wsprintf(str, "「%s, %s, %s」が選択されています", name, sex, address); MessageBox(hList, str, "OK", MB_OK); } return; }
さて、新しいスタイルのLVS_EX_CHECKBOXESを指定した時、どのアイテムが チェックされているかを知るのにListView_GetNextItemは使えません。 仕方がないので、全アイテム数を調べてそれぞれのアイテムについて ListView_GetCheckStateマクロでチェックされているかどうかを調べています。 アイテム数が少ない場合はこれでよいのかもしれませんが、大量にある時は ちょっと問題です。もっとよい方法が他にあるのかもしれません。あるいは 将来ListView_GetNextItemマクロがバージョンアップされるのかもしれません。void CheckMyCheck(HWND hList) { int nCount, i; char str[256], name[64], sex[8], address[128]; nCount = ListView_GetItemCount(hList); for (i = 0; i < nCount; i++) { if (ListView_GetCheckState(hList, i) != 0) { ListView_GetItemText(hList, i, 0, name, sizeof(name)); ListView_GetItemText(hList, i, 1, sex, sizeof(sex)); ListView_GetItemText(hList, i, 2, address, sizeof(address)); wsprintf(str, "「%s, %s, %s」にチェックあり", name, sex, address); MessageBox(hList, str, "CHECKED", MB_OK); } } return; }
今回もあんまり目新しいことはやりませんでした。
Update 02/May/1999 By Y.Kumei