第201章 ツリービューのチェック項目を知る


前章で作ったプログラムで、チェックされた項目を知るにはどうしたらよいのでしょうか。 実はこれが結構めんどうなのです。



選択されている項目のHTREEITEMはTreeView_GetSelectionマクロ (第113章参照)で取得できます。 この項目について中身を知りたい時はTreeView_GetItemマクロを使用します。

BOOL TreeView_GetItem( HWND hwndTV, LPTVITEM pitem );

hwndTVはツリービューのハンドルです。

pitemは情報を取得する項目に対するTVITEM構造体のアドレスです。

(注意!)以前のTV_ITEM構造体はTVITEM構造体に 名前が変更になりました。この構造体については 第111章を参照して下さい。

この構造体を使って項目のテキストを取得したい時(HTREEITEMがわかっている時)は 次のようにします。

maskメンバにTVIF_HANDLE | TVIF_TEXTを設定
hItemメンバに調べたい項目のハンドル(HTREEITEM)を指定
pszTextメンバに取得した文字列を収納するバッファのアドレスを指定
cchTextMaxメンバにバッファのサイズを指定

この後TreeView_GetItemマクロを呼び出します。

さて、チェックがついているかどうかはどうすればわかるのでしょうか。 これは、TVITEM構造体のstateメンバを右に12ビットシフトさせます。 (ビット演算については C言語編第40章を参照して下さい。) そうするとチェックがついていると2、ついていないと1になります。 また、この場合maskメンバにTVIF_STATE、stateMaskメンバにTVIS_STATEIMAGEMASKが設定されていないと いけません。

これで、調べたい項目のHTREEITEMがわかっていると その項目のチェックの有無が調べられます。しかし、HTREEは どのように調べたらよいのでしょうか。 最初の項目はTreeView_GetRootマクロでわかります。

HTREEITEM TreeView_GetRoot( HWND hwndTV );

そのあとTreeView_GetNextSibling, TreeView_GetChildマクロなどを 駆使するとツリービュー中のすべての項目のHTREEITEMが取得 できそうです。しかし、これが結構難しいのです。

HTREEITEM TreeView_GetNextSibling( HWND hwndTV, HTREEITEM hitem ); HTREEITEM TreeView_GetChild( HWND hwndTV, HTREEITEM hitem, );

そこで、今回は少しずるをして、安直な方法で ツリービュー中のすべての項目のハンドルを取得します。 それぞれについてチェックがされているかどうかを 調べて、チェックされているとその項目のテキストを メッセージボックスで表示させます。
どのようにして全項目のハンドルを取得するかというと

1.TreeView_GetRootマクロで最初の項目のハンドルを取得 2.TreeView_Expandマクロでこの項目を展開 3.TreeView_GetItemマクロでこの項目についての状態を取得 4.チェックがついているかどうかを調べる 5.チェックがついていたらメッセージボックスでテキストを表示 6.TreeViw_GetNextItemマクロの最後の引数をTVGN_NEXTVISIBLE   にして次の見える項目を取得 7.TreeView_Expandマクロでこの項目を展開 8.この項目のハンドルをTVITEM構造体に設定

3.−8.を繰り返します。要するにツリービューを展開して いって折りたたまれている項目をなくして見えている項目のハンドルを 次々と取得していくわけです。 6.はTreeView_GetNextVisibleマクロを使っても同じ事ができます。

BOOL TreeView_Expand( HWND hwndTV, HTREEITEM hItem, UINT flag );

hwndTVにはツリービューのハンドルを指定します。
hItemには項目のハンドルを指定します。
flagには次のものを指定します。
TVE_COLLAPSEツリービューを縮小します
TVE_COLLAPSERESETツリービューを縮小して子項目を 削除します。
TVE_COLLAPSEも同時に指定して下さい
TVE_EXPANDツリービューを展開します
TVE_TOGGLE展開されていれば縮小し、
縮小されていれば展開します

HTREEITEM TreeView_GetNextItem( HWND hwndTV, HTREEITEM hitem, UINT flag );

hwndTVにはツリービューのハンドルを指定します。
hitemには項目のハンドルを指定します。
flagには次の中から1つだけを指定します。
TVGN_CARET現在選択されている項目のハンドルを取得する
TVGN_CHILDhitemで指定した項目の最初の 子項目のハンドルを取得する
TVGN_DROPHILITED&D操作のターゲットの項目のハンドル を取得する
TVGN_FIRSTVISIBLE 最初に見える項目のハンドルを取得する
TVGN_NEXT次の兄弟項目のハンドルを取得する
TVGN_NEXTVISIBLE指定の項目の次に見えている項目のハンドルを 取得する
TVGN_PARENT指定の項目の親項目のハンドルを取得する
TVGN_PREVIOUS前の兄弟項目のハンドルを取得する
TVGN_PREVIOUSVISIBLE指定の項目の前に見えている 最初の項目のハンドルを取得する
TVGN_ROOTツリービューの最初の項目のハンドルを取得する

さて、チェックのついてる項目がウィンドウの大きさ等で影に隠れていていて 見えない場合、これをスクロールなどして見えるようにすると ユーザーにとっては親切設計です。これを実現するのが TreeView_EnsureVisibleマクロです。これはすでに 第114章に解説があるので参照して下さい。

では、プログラムを見てみましょう。

// newtree2.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "ツリービュー(&T)" BEGIN MENUITEM "チェック項目の確認(&C)", IDM_GETCHECK MENUITEM "選択項目の確認(&S)", IDM_GETSELECT END END

普通のメニューのリソース・スクリプトです。

// newtree2.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 MakeMyTree(HWND); void InsertMyItem(HWND); void GetMyCheck(HWND); void GetMySelect(HWND); char szClassName[] = "newtree2"; //ウィンドウクラス 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, "猫でもわかるTree View", //タイトルバーにこの名前が表示されます 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; static HWND hTree; INITCOMMONCONTROLSEX ic; int wx, wy; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_GETCHECK: GetMyCheck(hTree); SetFocus(hTree); break; case IDM_GETSELECT: GetMySelect(hTree); SetFocus(hTree); break; } break; case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_TREEVIEW_CLASSES; InitCommonControlsEx(&ic); hTree = MakeMyTree(hWnd); SendMessage(hTree, TVM_SETITEMHEIGHT, (WPARAM)16, 0); InsertMyItem(hTree); break; case WM_SIZE: wx = LOWORD(lp); wy = HIWORD(lp); MoveWindow(hTree, 0, 0, wx, wy, TRUE); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hTree); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メニューからIDM_GETCHECKが選択されたら自作関数のGetMyCheckを 呼び出します。同様にIDM_GETSELECTが選択されたらGetMySelectを 呼び出します。

HWND MakeMyTree(HWND hWnd) { HWND hTree; hTree = CreateWindowEx(0, //拡張スタイル WC_TREEVIEW, //ウィンドウクラス "", //ウィンドウの名前 WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_CHECKBOXES | TVS_SINGLEEXPAND | TVS_FULLROWSELECT | TVS_TRACKSELECT,//ウィンドウスタイル 0, 0, 0, 0,//位置、大きさ hWnd,//親ウィンドウ (HMENU)100,//ID hInst,//インスタンスハンドル NULL); return hTree; }

ツリービューを作る関数です。前章と同じです。

void InsertMyItem(HWND hTree) { HTREEITEM hAsia, hEurope, hJapan; TV_INSERTSTRUCT tv; ZeroMemory(&tv, sizeof(TV_INSERTSTRUCT)); tv.hInsertAfter = TVI_LAST; tv.item.mask = TVIF_TEXT; tv.hParent = TVI_ROOT; tv.item.pszText = "アジア"; hAsia = TreeView_InsertItem(hTree, &tv); tv.item.pszText = "ヨーロッパ"; hEurope = TreeView_InsertItem(hTree, &tv); tv.hParent = hAsia; tv.item.pszText = "日本"; hJapan = TreeView_InsertItem(hTree, &tv); tv.hParent = hAsia; tv.item.pszText = "中華人民共和国"; TreeView_InsertItem(hTree, &tv); tv.hParent = hEurope; tv.item.pszText = "イギリス"; TreeView_InsertItem(hTree, &tv); tv.hParent = hEurope; tv.item.pszText = "ドイツ"; TreeView_InsertItem(hTree, &tv); tv.hParent = hEurope; tv.item.pszText = "オランダ"; TreeView_InsertItem(hTree, &tv); tv.hParent = hJapan; tv.item.pszText = "北海道"; TreeView_InsertItem(hTree, &tv); tv.hParent = hJapan; tv.item.pszText = "本州"; TreeView_InsertItem(hTree, &tv); tv.hParent = hJapan; tv.item.pszText = "四国"; TreeView_InsertItem(hTree, &tv); tv.hParent = hJapan; tv.item.pszText = "九州"; TreeView_InsertItem(hTree, &tv); tv.hParent = hJapan; tv.item.pszText = "沖縄"; TreeView_InsertItem(hTree, &tv); return; }

ツリービューに項目を追加する関数です。前章と同じです。

void GetMyCheck(HWND hTree) { TVITEM tvItem; HTREEITEM hItem; char szStr[256]; memset(&tvItem, 0, sizeof(TVITEM)); hItem = TreeView_GetRoot(hTree); tvItem.mask = TVIF_HANDLE | TVIF_STATE | TVIF_TEXT; tvItem.hItem = hItem; tvItem.stateMask = TVIS_STATEIMAGEMASK; tvItem.pszText = szStr; tvItem.cchTextMax = 256; TreeView_Expand(hTree, hItem, TVE_EXPAND); while (1) { TreeView_GetItem(hTree, &tvItem); if((BOOL)(tvItem.state >> 12) -1) { TreeView_EnsureVisible(hTree, hItem); MessageBox(hTree, szStr, "OK", MB_OK); } hItem = TreeView_GetNextItem(hTree, hItem, TVGN_NEXTVISIBLE); TreeView_Expand(hTree, hItem, TVE_EXPAND); tvItem.hItem = hItem; if (hItem == NULL) return; } return; }

今までの説明を読めば特に説明は不要と思いますが、 チェックされているかどうかを調べる時TVITEM構造体の stateMaskメンバにTVIS_STATEIMAGEMASK, msskメンバに TVIF_STATEを指定するのを 忘れないでください。

void GetMySelect(HWND hTree) { HTREEITEM hItem; TVITEM ti; char szStr[256]; memset(&ti, 0, sizeof(TVITEM)); ti.mask = TVIF_HANDLE | TVIF_TEXT; ti.pszText = szStr; ti.cchTextMax = 256; hItem = TreeView_GetSelection(hTree); ti.hItem = hItem; TreeView_GetItem(hTree, &ti); MessageBox(hTree, szStr, "OK", MB_OK); return; }

選択された項目のテキストを表示する関数です。
TreeView_GetSelectionマクロで選択された項目のハンドルを 取得してTreeView_GetItemマクロでその項目のテキストを 取得しています。

さて、今回はツリービューに関するいろいろなマクロが 登場しましたが、これらはツリービューに対して TVM_***というメッセージを送ることでも実現できます。 ヘルプ等で調べてみてください。


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

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