第111章 ツリービューの基礎


今回は、ツリービューをやります。ツリービューというのは エクスプローラの左半分みたいなやつです。

左の図のようなものを作ります。ディレクトリなどの 階層構造をあらわすのには便利ですね。マイナスボタンを押すと それより下の階層は表示されなくなりボタンがプラスに変わります。



ツリービューもコモンコントロールの一つです。 作り方はリストビューと良く似ています。

1.コモンコントロールの準備   commctrl.hのインクルード   comctl32.libをプロジェクトに加える   InitCommonControls関数を実行してコモンコントロールを初期化 2.クラス名をWC_TREEVIEWにしてCreateWindowEx関数を実行 3.親ウィンドウのサイズが変わったときの対策 4.TreeView_InsertItemマクロで親項目や子項目を追加する

さて、TreeView_InsertItemマクロは次のようになっています。

HTREEITEM TreeView_InsertItem( hwnd, lpis );

hwndはツリービューのウィンドウハンドルです。
lpisはTV_INSERTSTRUCT構造体へのポインタです。
戻り値は新しい項目に対するハンドルです。

typedef struct _TV_INSERTSTRUCT { //tvins HTREEITEM hParent; HTREEITEM hInsertAfter; TV_ITEM item; } TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT;

hParentは親アイテムのハンドルです。これがTVI_ROOTまたはNULLの時は ツリービューコントロールのルートに挿入されます。
hInsertAfterは挿入後の位置を示します。TVI_FIRST, TVI_LAST, TVI_SORT のいずれかが来ます。
itemは加えられたアイテムについての情報です。

typedef struct _TV_ITEM { //tvi UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; } TV_ITEM, FAR *LPTV_ITEM;

maskはどの構造体メンバが有効かを示します。 TVIF_TEXTだとpszTextメンバが有効となります。
後のメンバについては必要が生じたとき解説します。

これだけでもっとも単純なツリービューが作れます。 早速プログラムを見てみましょう。

// treevw01.cpp #define STRICT #include <windows.h> #include <commctrl.h> #define ID_MYTREE 100 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void AddItem(HWND); char szClassName[] = "treevw01"; //ウィンドウクラス HINSTANCE hInst; 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 = NULL; //メニュー名 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; static HWND hTree; switch (msg) { case WM_CREATE: InitCommonControls(); //コモンコントロールの初期化 hTree = CreateWindowEx(0, WC_TREEVIEW, "", WS_CHILD | WS_BORDER | WS_VISIBLE | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT, 0, 0, 0, 0, hWnd, (HMENU)ID_MYTREE, hInst, NULL); AddItem(hTree); break; case WM_SIZE: MoveWindow(hTree, 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; }

親ウィンドウができたらすぐに(WM_CREATE)コモンコントロールを 初期化します。そしてツリービューのウィンドウを作成します。 ツリービューのスタイルにはTVS_HASBUTTON, TVS_HASLINE, TVS_LINESATROOTなどがあります。TVS_HASBUTTONはプラスと マイナスのボタンを表示します。TVS_HASLINEは項目の階層を 破線で表示します。TVS_LINESATROOTはルートにある項目を 破線で結びます。これでよくわからないときは 各スタイルを付けたりはずしたりして実際にプログラムを 作って試してみてください。

親の大きさが変わったら(WM_SIZE)ツリービューのウインドウの 大きさも矛盾のないようにします。

void AddItem(HWND hTree) { HTREEITEM hParent1, hParent2, hParent3, hChild1, hChild2; TV_INSERTSTRUCT tv; memset((char *)&tv, '\0', sizeof(tv)); tv.hInsertAfter = TVI_LAST; tv.item.mask = TVIF_TEXT; tv.hParent = TVI_ROOT; tv.item.pszText = "粂井"; hParent1 = TreeView_InsertItem(hTree, &tv); tv.item.pszText = "田中"; hParent2 = TreeView_InsertItem(hTree, &tv); tv.item.pszText = "佐藤"; hParent3 = TreeView_InsertItem(hTree, &tv); tv.hParent = hParent1; tv.item.pszText = "康孝"; hChild1 = TreeView_InsertItem(hTree, &tv); tv.item.pszText = "ひとみ"; hChild2 = TreeView_InsertItem(hTree, &tv); tv.hParent = hChild1; tv.item.pszText = "志麻"; TreeView_InsertItem(hTree, &tv); tv.hParent = hChild1; tv.item.pszText = "櫻都"; TreeView_InsertItem(hTree, &tv); tv.hParent = hParent2; tv.item.pszText = "マイケル"; TreeView_InsertItem(hTree, &tv); tv.hParent = hParent3; tv.item.pszText = "パトリシア"; TreeView_InsertItem(hTree, &tv); return; }

項目を挿入する関数です。項目の親子関係に注意してください。

今回は単純でした。


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

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