第109章 リストビューにアイコンを付ける


今回はリストビューの項目にアイコンを付けてみます。さらに、 リストビューの表示形式を変えれるようにします。また、 前回は項目を編集するのに項目を選択して、さらにマウスで クリックしていましたが、これをメニューからできるようにします。



今までの表示形式(LVS_REPORT)に小さいアイコン(16*16)を つけると左のようになります。


大きいアイコン(32*32)(LVS_ICON)にすると左のようになります。 この時、サブアイテムは表示されません。
この他に小さいアイコン(LVS_SMALLICON)、リスト形式(LVS_LIST) があります。これらもサブアイテムは表示されません。 小さいアイコン、大きいアイコン表示ではウィンドウの大きさに 合わせて配置を換えることができます。リスト形式では 縦1列に表示されます。(実際に作って動かしてみるとすぐにわかります。)

まずは前準備として小さいアイコン、大きいアイコンをリソースエジタで 作っておきます。リソース名は"S1", "S2", "S3", "S4", "MYICON1", "MYICON2", "MYICON3", "MYICON4"としておきます。
メニューの階層表示は次のようにしておきます。

ファイル編集表示
終了(IDM_END)項目の削除(IDM_DEL)
項目の編集(IDM_EDIT)
大きいアイコン(IDM_LARGE)
小さいアイコン(IDM_SMALL)
リスト表示(IDM_LIST)
詳細表示(IDM_TABLE)
では、プログラムをみてみます。

// listvw04.rcの一部 //  自力でリソーススクリプトを作る人は参考にしてください。 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "編集(&X)" BEGIN MENUITEM "項目の削除(&D)", IDM_DEL MENUITEM "項目の編集(&E)", IDM_EDIT END POPUP "表示(&V)" BEGIN MENUITEM "大きいアイコン(&L)", IDM_LARGE MENUITEM "小さいアイコン(&S)", IDM_SMALL MENUITEM "リスト表示(&A)", IDM_LIST MENUITEM "詳細表示(&D)", IDM_TABLE END END ///////////////////////////////////////////////////////////////////////////// // // Icon // MYICON1 ICON DISCARDABLE "myicon1.ico" MYICON2 ICON DISCARDABLE "myicon2.ico" MYICON3 ICON DISCARDABLE "myicon3.ico" MYICON4 ICON DISCARDABLE "myicon4.ico" S1 ICON DISCARDABLE "s1.ico" S2 ICON DISCARDABLE "s2.ico" S3 ICON DISCARDABLE "s3.ico" S4 ICON DISCARDABLE "s4.ico"

別にどうということもないリソース・スクリプトです。

// listvw04.cpp #define STRICT #define ID_LISTVIEW 100 #include <windows.h> #include <commctrl.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void SetInitialData(HWND); char szClassName[] = "listvw04"; //ウィンドウクラス HINSTANCE hInst; //インスタンスハンドル(保存) HWND hList; //リストビューのハンドル HIMAGELIST hImage, hSmall;//イメージリストハンドル int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

いつもと同じですがイメージリストのハンドルをグローバル変数にしておきました。 イメージ付きタブコントロール(第71章)の ところでやったようにリストビューにアイコンを付けるにはイメージリストを使います。 イメージリストについては第70章を参照してください。

//ウィンドウ・クラスの登録 BOOL 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 hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance;//グローバル変数に保存 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, iSelected; int nItem; LV_DISPINFO *lvinfo; char buf[64]; static HWND hEdit; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_DEL: while(1) { nItem = ListView_GetNextItem( hList, -1, LVNI_ALL | LVNI_SELECTED); if (nItem == -1) break; ListView_DeleteItem(hList, nItem); ListView_Arrange(hList, LVA_ALIGNLEFT); } break; case IDM_EDIT: iSelected = ListView_GetNextItem(hList, -1, LVNI_ALL | LVNI_SELECTED); ListView_EditLabel(hList, iSelected); break; case IDM_LARGE: SetWindowLong(hList, GWL_STYLE, WS_CHILD | WS_VISIBLE | LVS_EDITLABELS | LVS_ICON); ListView_Arrange(hList, LVA_ALIGNLEFT); break; case IDM_SMALL: SetWindowLong(hList, GWL_STYLE, WS_CHILD | WS_VISIBLE | LVS_EDITLABELS | LVS_SMALLICON); ListView_Arrange(hList, LVA_ALIGNLEFT); break; case IDM_LIST: SetWindowLong(hList, GWL_STYLE, WS_CHILD | WS_VISIBLE | LVS_EDITLABELS | LVS_LIST); break; case IDM_TABLE: SetWindowLong(hList, GWL_STYLE, WS_CHILD | WS_VISIBLE | LVS_EDITLABELS | LVS_REPORT); break; } break; case WM_NOTIFY: if ((int)wp == ID_LISTVIEW) { lvinfo = (LV_DISPINFO *)lp; switch (lvinfo->hdr.code) { case LVN_BEGINLABELEDIT: hEdit = ListView_GetEditControl(hList); break; case LVN_ENDLABELEDIT: GetWindowText(hEdit, buf, sizeof(buf)); ListView_SetItemText(hList, lvinfo->item.iItem, 0, buf); break; } } break; case WM_CREATE: InitCommonControls(); hList = CreateWindowEx(0, WC_LISTVIEW, "", WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_EDITLABELS, 0, 0, 0, 0, hWnd, (HMENU)ID_LISTVIEW, hInst, NULL); SetInitialData(hList); break; case WM_SIZE: MoveWindow(hList, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); ListView_Arrange(hList, LVA_ALIGNLEFT); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: ImageList_Destroy(hImage); ImageList_Destroy(hSmall); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メニューから「項目の削除」(IDM_DEL)が選択されたときの処理は 前回にほぼ同じですが、最後にListView_Arrangeが付け加えられて いることに注意してください。これは、大きいアイコン表示および 小さいアイコン表示の時前回のままだと削除したところが空白に なってみっともないからです。

BOOL ListView_Arrange( HWND hwnd, UINT code );

hwndは当然リストビューのハンドルが来ます。

codeには、整列の仕方を指示します。
LVA_ALIGNLEFTは項目をウィンドウの左に揃えます。
LVA_ALIGNTOPは項目をウィンドウの上に揃えます。
LVA_DEFAULTは現在の配置スタイルに合わせます。
LVA_SNAPTOGRIDについては後の章で解説する予定です。

メニューから「項目の編集」(IDM_EDIT)が選択されたら まず、ListView_GetNextItemマクロで選択されている項目番号を知ります。 そしてListView_EditLabelを実行すれば項目が編集状態になります。

HWND ListView_EditLabel( HWND hwnd, int iItem );

hwndはリストビューのハンドルです。
iItemは項目番号です。

さて、このマクロの戻り値はエジットコントロールのハンドルです。 通知メッセージの処理は前章と同じです。

では、次にリストビューの表示形式を変えるにはどうしたらよいのでしょうか。 リストビューの表示形式にはLVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICONが あります。これは、CreateWindowEx関数の引数で指定しました。

作ってしまったウィンドウのスタイルを変えるにはどうするんだ?

と思われるかもしれませんが、これはSetWindowLong関数を使って変更することが できます。これは第36章のウィンドウのサブクラス化 のところで出てきました。

SetWindowLong(hList, GWL_STYLE, WS_CHILD | WS_VISIBLE | LVS_EDITLABELS | LVS_ICON);

とすればリストビューのウィンドウスタイルを第3引数のように変更することができます。 これで、IDM_LARGE, IDM_SMALL, IDM_LIST, IDM_TABLEが選択されたときの プログラムの方法がわかりますね。

今回はWM_SIZEメッセージの時もListView_Arrangeマクロを入れておく必要があります。

イメージリストを使ってるのでプログラム終了時にImageList_Destroyをしておく 必要があります。

// 初期データ表示用 void SetInitialData(HWND hList) { LV_COLUMN lvcol; LV_ITEM item; hImage = ImageList_Create(32, 32, ILC_COLOR4, 4, 0); hSmall = ImageList_Create(16, 16, ILC_COLOR4, 4, 0); ListView_SetImageList(hList, hImage, LVSIL_NORMAL); ListView_SetImageList(hList, hSmall, LVSIL_SMALL); ImageList_AddIcon(hImage, LoadIcon(hInst, "MYICON1")); ImageList_AddIcon(hImage, LoadIcon(hInst, "MYICON2")); ImageList_AddIcon(hImage, LoadIcon(hInst, "MYICON3")); ImageList_AddIcon(hImage, LoadIcon(hInst, "MYICON4")); ImageList_AddIcon(hSmall, LoadIcon(hInst, "S1")); ImageList_AddIcon(hSmall, LoadIcon(hInst, "S2")); ImageList_AddIcon(hSmall, LoadIcon(hInst, "S3")); ImageList_AddIcon(hSmall, LoadIcon(hInst, "S4")); 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 = 200; lvcol.pszText = "住所"; lvcol.iSubItem = 1; ListView_InsertColumn(hList, 1, &lvcol); item.mask = LVIF_TEXT | LVIF_IMAGE; item.pszText = "粂井康孝"; item.iItem = 0; item.iSubItem = 0; item.iImage = 0; ListView_InsertItem(hList, &item); item.mask = LVIF_TEXT; item.pszText = "北海道旭川市"; item.iItem = 0; item.iSubItem = 1; ListView_SetItem(hList, &item); item.mask = LVIF_TEXT | LVIF_IMAGE; item.pszText = "粂井ひとみ"; item.iItem = 1; item.iSubItem = 0; item.iImage = 1; ListView_InsertItem(hList, &item); item.mask = LVIF_TEXT; item.pszText = "東京都千代田区"; item.iItem = 1; item.iSubItem = 1; ListView_SetItem(hList, &item); item.mask = LVIF_TEXT | LVIF_IMAGE; item.pszText = "粂井志麻"; item.iItem = 2; item.iSubItem = 0; item.iImage = 2; ListView_InsertItem(hList, &item); item.mask = LVIF_TEXT; item.pszText = "北海道中富良野町"; item.iItem = 2; item.iSubItem = 1; ListView_SetItem(hList, &item); item.mask = LVIF_TEXT | LVIF_IMAGE; item.pszText = "粂井櫻都"; item.iItem = 3; item.iSubItem = 0; item.iImage = 3; ListView_InsertItem(hList, &item); item.mask = LVIF_TEXT; item.pszText = "北海道深川市"; item.iItem = 3; item.iSubItem = 1; ListView_SetItem(hList, &item); return; }

さて、イメージリストにアイコンを表示するという本題にやっと入れます。 やり方は簡単です。

1.ImageList_Createでイメージリストを作る。 2.ListView_SetImageListでイメージリストをリストビューにセットする。 3.アイコンを表示する項目のmaskメンバにLVIF_IMAGEを加える。 3.アイコンを表示する項目のiImageメンバにイメージリストのインデックスを指定する。

というようにします。

HIMAGELIST ListView_SetImageList( HWND hwnd, HIMAGELIST himl, int iImageList );

hwndにはリストビューのハンドルを指定します。
himlにはイメージリストのハンドルを指定します。
iImageListにはイメージリストのタイプを指定します。
タイプにはLVSIL_NORMAL, LVSIL_SMALL, LVSIL_STATEの中から選びます。 それぞれ大きいアイコン、小さいアイコン、状態イメージを持つイメージリストを表します。

さて、できあがったプログラムをいろいろ動かしてみて不満はありませんか。 「名前」「住所」などの列の名前をクリックするとボタン様に動きます。 しかし、それだけです。これをクリックしたときその列がABC順などに 並び変わるとうれしいですね。


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

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