選択されている項目のHTREEITEMはTreeView_GetSelectionマクロ
(第113章参照)で取得できます。
この項目について中身を知りたい時はTreeView_GetItemマクロを使用します。
hwndTVはツリービューのハンドルです。BOOL TreeView_GetItem( HWND hwndTV, LPTVITEM pitem );
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マクロでわかります。
そのあとTreeView_GetNextSibling, TreeView_GetChildマクロなどを 駆使するとツリービュー中のすべての項目のHTREEITEMが取得 できそうです。しかし、これが結構難しいのです。HTREEITEM TreeView_GetRoot( HWND hwndTV );
そこで、今回は少しずるをして、安直な方法で ツリービュー中のすべての項目のハンドルを取得します。 それぞれについてチェックがされているかどうかを 調べて、チェックされているとその項目のテキストを メッセージボックスで表示させます。HTREEITEM TreeView_GetNextSibling( HWND hwndTV, HTREEITEM hitem ); HTREEITEM TreeView_GetChild( HWND hwndTV, HTREEITEM hitem, );
3.−8.を繰り返します。要するにツリービューを展開して いって折りたたまれている項目をなくして見えている項目のハンドルを 次々と取得していくわけです。 6.はTreeView_GetNextVisibleマクロを使っても同じ事ができます。1.TreeView_GetRootマクロで最初の項目のハンドルを取得 2.TreeView_Expandマクロでこの項目を展開 3.TreeView_GetItemマクロでこの項目についての状態を取得 4.チェックがついているかどうかを調べる 5.チェックがついていたらメッセージボックスでテキストを表示 6.TreeViw_GetNextItemマクロの最後の引数をTVGN_NEXTVISIBLE にして次の見える項目を取得 7.TreeView_Expandマクロでこの項目を展開 8.この項目のハンドルをTVITEM構造体に設定
hwndTVにはツリービューのハンドルを指定します。BOOL TreeView_Expand( HWND hwndTV, HTREEITEM hItem, UINT flag );
TVE_COLLAPSE | ツリービューを縮小します |
TVE_COLLAPSERESET | ツリービューを縮小して子項目を
削除します。 TVE_COLLAPSEも同時に指定して下さい |
TVE_EXPAND | ツリービューを展開します |
TVE_TOGGLE | 展開されていれば縮小し、 縮小されていれば展開します |
hwndTVにはツリービューのハンドルを指定します。HTREEITEM TreeView_GetNextItem( HWND hwndTV, HTREEITEM hitem, UINT flag );
TVGN_CARET | 現在選択されている項目のハンドルを取得する |
TVGN_CHILD | hitemで指定した項目の最初の 子項目のハンドルを取得する |
TVGN_DROPHILITE | D&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; }
メニューからIDM_GETCHECKが選択されたら自作関数のGetMyCheckを 呼び出します。同様にIDM_GETSELECTが選択されたらGetMySelectを 呼び出します。//ウィンドウプロシージャ 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; }
ツリービューを作る関数です。前章と同じです。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; }
今までの説明を読めば特に説明は不要と思いますが、 チェックされているかどうかを調べる時TVITEM構造体の stateMaskメンバにTVIS_STATEIMAGEMASK, msskメンバに TVIF_STATEを指定するのを 忘れないでください。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; }
選択された項目のテキストを表示する関数です。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; }
さて、今回はツリービューに関するいろいろなマクロが 登場しましたが、これらはツリービューに対して TVM_***というメッセージを送ることでも実現できます。 ヘルプ等で調べてみてください。
Update 10/May/1999 By Y.Kumei