第107章 リストビューに列と項目を追加する


今回は、ユーザーがリストビューに列を追加したり、項目を 追加できるようにします。もちろんサブ項目もユーザーが入力します。 前回に比べて特に新しい知識は必要としません。 早速見てみることにします。



起動したばかりの時はリストビューには何も表示されていません。 (メニューの高さが高くなったように見える)メニューも付けました。 「ファイル」の下には「終了」があります。「編集」の下には左の図のように 「列の追加」「項目の追加」「サブ項目の設定」があります。



「列の追加」を選択すると左のようなダイアログボックスが出てきます。 「氏名」「住所」「電話番号」などを追加してみます。



そうすると左のように「列」が追加されました。



今度は「項目の追加」を選択します。そうすると左のようなダイアログボックスが 出てきます。「粂井康孝」「粂井ひとみ」「粂井志麻」「粂井櫻都」などを 追加してみます。



そうすると左の図のように「項目」が追加されました。



今度は「サブ項目の設定」を選択します。 そうすると左の図のようなダイアログボックスが出てきます。 この例では「粂井康孝」の「住所」は項目番号が0でサブ項目番号は1です。 「粂井櫻都」の「電話番号」は項目番号3でサブ項目番号は2です。 項目番号とサブ項目番号の意味がおわかりになったでしょうか。



はい、全部を埋めると左のようになりました。



では、プログラムを見ていくことにします。

// listvw02.rcの一部 // リソースエジタを使わずに自力で書く人は参考にしてください ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "編集(&E)" BEGIN MENUITEM "列の追加(&L)", IDM_INSCOLUMN MENUITEM "項目の追加(&I)", IDM_INSITEM MENUITEM "サブ項目の設定(&S)", IDM_SETSUB END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 146, 73 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "列の追加" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,51,50,14 PUSHBUTTON "キャンセル",IDCANCEL,89,51,50,14 EDITTEXT IDC_EDIT1,38,7,101,14,ES_AUTOHSCROLL LTEXT "列の名前:",IDC_STATIC,7,7,32,8 LTEXT "列の幅:",IDC_STATIC,7,33,25,8 EDITTEXT IDC_EDIT2,40,30,40,13,ES_AUTOHSCROLL END MYDLG2 DIALOG DISCARDABLE 0, 0, 163, 47 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "項目の追加" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,21,26,50,14 PUSHBUTTON "キャンセル",IDCANCEL,90,26,50,14 LTEXT "項目の名前:",IDC_STATIC,7,7,39,8 EDITTEXT IDC_EDIT1,59,7,97,12,ES_AUTOHSCROLL END MYDLG3 DIALOG DISCARDABLE 0, 0, 155, 93 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "サブ項目の設定" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,19,72,50,14 PUSHBUTTON "キャンセル",IDCANCEL,85,72,50,14 LTEXT "項目番号:",IDC_STATIC,7,7,32,8 EDITTEXT IDC_EDIT1,65,7,35,12,ES_AUTOHSCROLL LTEXT "サブ項目番号:",IDC_STATIC,7,27,45,8 EDITTEXT IDC_EDIT2,67,25,35,12,ES_AUTOHSCROLL LTEXT "テキスト:",IDC_STATIC,7,49,28,8 EDITTEXT IDC_EDIT3,47,45,100,14,ES_AUTOHSCROLL END

メニューとダイアログボックスのリソーススクリプトです。 実際の図とリソーススクリプト中のシンボルなどを参考に 同様のものを作ってください。

// listvw01.cpp #define STRICT #define ID_LISTVIEW 100 #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK ColumnProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK ItemProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK SubitemProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void InsColumn(char *, int, int); void InsItem(char *); void SetSubitem(int, int, char *); char szClassName[] = "listvw01"; //ウィンドウクラス HINSTANCE hInst; //インスタンスハンドル(保存) HWND hList; //リストビューのハンドル int sub = -1; //iSubItem int it = -1; 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; }

これもいつもと同じです。インスタンスハンドルを保存しています。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_INSCOLUMN: DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)ColumnProc); break; case IDM_INSITEM: DialogBox(hInst, "MYDLG2", hWnd, (DLGPROC)ItemProc); break; case IDM_SETSUB: DialogBox(hInst, "MYDLG3", hWnd, (DLGPROC)SubitemProc); break; } break; case WM_CREATE: InitCommonControls(); hList = CreateWindowEx(0, WC_LISTVIEW, "", WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, 0, 0, hWnd, (HMENU)ID_LISTVIEW, hInst, NULL); break; case WM_SIZE: MoveWindow(hList, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

「列の追加」(IDM_INSCOLUMN)が選ばれたら"MYDLG"ダイアログボックスを 呼び出します。同様に「項目の追加」「サブ項目の設定」が選ばれたらそれぞれ "MYDLG2", "MYDLG3"ダイアログボックスを呼び出します。

WM_CREATEがきたらコモンコントロールの初期化をします。そして リストビューを作ります。

親の大きさが変わったら(WM_SIZE)リストビューも親のクライアント領域の 大きさに合わせます。

ということで、親のウィンドウプロシージャは前回より簡単でした。

LRESULT CALLBACK ColumnProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { char buf1[256], buf2[64]; int cx; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: EndDialog(hDlg, IDOK); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), buf1, sizeof(buf1)); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT2), buf2, sizeof(buf2)); cx = atoi(buf2); sub++; InsColumn(buf1, cx, sub); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } break; } return FALSE; }

「列の追加」ダイアログボックスのプロシージャです。 OKボタンが押されたら、列の名前と幅を取得します。そして 自作関数InsColumnを呼び出します。

void InsColumn(char *str, int cx, int iSub) { LV_COLUMN col; col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; col.fmt = LVCFMT_LEFT; col.cx = cx; col.pszText = str; col.iSubItem = iSub; ListView_InsertColumn(hList, iSub, &col); return; }

これは、特に説明は不要ですね。列の追加を関数にしただけです。

LRESULT CALLBACK ItemProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { char buf[256]; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: EndDialog(hDlg, IDOK); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), buf, sizeof(buf)); InsItem(buf); case IDCANCEL: EndDialog(hDlg, IDOK); return TRUE; } break; } return FALSE; }

「項目の追加」ダイアログボックスのプロシージャです。 OKボタンが押されたら項目名を取得して自作関数InsItem()を呼んでいます。

void InsItem(char *str) { LV_ITEM item; it++; item.mask = LVIF_TEXT; item.pszText = str; item.iItem = it; item.iSubItem = 0; ListView_InsertItem(hList, &item); return; }

これは、項目を追加するところを関数にしただけです。

LRESULT CALLBACK SubitemProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { char buf1[32], buf2[32], buf3[256]; int itmno, subino; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: EndDialog(hDlg, IDOK); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), buf1, sizeof(buf1)); itmno = atoi(buf1); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT2), buf2, sizeof(buf2)); subino = atoi(buf2); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT3), buf3, sizeof(buf3)); SetSubitem(itmno, subino, buf3); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } break; } return FALSE; }

「サブ項目の設定」ダイアログボックスのプロシージャです。 OKボタンが押されたら、項目番号、サブ項目番号、そこに表示される テキストを取得します。そして自作関数SetSubitem関数を呼び出します。

void SetSubitem(int item, int subitem, char *str) { LV_ITEM itm; itm.mask = LVIF_TEXT; itm.pszText = str; itm.iItem = item; itm.iSubItem = subitem; ListView_SetItem(hList, &itm); return; }

これは、サブ項目の設定を関数にしただけです。

と、いうことで今回は少し長いプログラムでしたが、 一つ一つを見ていくと別にどうということもないものでした。 このプログラムを作って実行してみると、きっといろいろな不満が 出てくるでしょう。次回から予想される不満を少しずつ解決していきます。


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

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