今までの表示形式(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"
いつもと同じですがイメージリストのハンドルをグローバル変数にしておきました。 イメージ付きタブコントロール(第71章)の ところでやったようにリストビューにアイコンを付けるにはイメージリストを使います。 イメージリストについては第70章を参照してください。// 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; }
いつもの通りです。メニュー名を忘れないでください。//ウィンドウ・クラスの登録 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; }
メニューから「項目の削除」(IDM_DEL)が選択されたときの処理は 前回にほぼ同じですが、最後にListView_Arrangeが付け加えられて いることに注意してください。これは、大きいアイコン表示および 小さいアイコン表示の時前回のままだと削除したところが空白に なってみっともないからです。//ウィンドウプロシージャ 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; }
hwndは当然リストビューのハンドルが来ます。BOOL ListView_Arrange( HWND hwnd, UINT code );
codeには、整列の仕方を指示します。
LVA_ALIGNLEFTは項目をウィンドウの左に揃えます。
LVA_ALIGNTOPは項目をウィンドウの上に揃えます。
LVA_DEFAULTは現在の配置スタイルに合わせます。
LVA_SNAPTOGRIDについては後の章で解説する予定です。
メニューから「項目の編集」(IDM_EDIT)が選択されたら まず、ListView_GetNextItemマクロで選択されている項目番号を知ります。 そしてListView_EditLabelを実行すれば項目が編集状態になります。
hwndはリストビューのハンドルです。HWND ListView_EditLabel( HWND hwnd, int iItem );
さて、このマクロの戻り値はエジットコントロールのハンドルです。 通知メッセージの処理は前章と同じです。
では、次にリストビューの表示形式を変えるにはどうしたらよいのでしょうか。 リストビューの表示形式にはLVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICONが あります。これは、CreateWindowEx関数の引数で指定しました。
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メンバにイメージリストのインデックスを指定する。
hwndにはリストビューのハンドルを指定します。HIMAGELIST ListView_SetImageList( HWND hwnd, HIMAGELIST himl, int iImageList );
さて、できあがったプログラムをいろいろ動かしてみて不満はありませんか。 「名前」「住所」などの列の名前をクリックするとボタン様に動きます。 しかし、それだけです。これをクリックしたときその列がABC順などに 並び変わるとうれしいですね。
Update Feb/20/1998 By Y.Kumei