ダイアログボックスにツリービューを付ける

ツリービュー1

今回は、ダイアログボックスにツリービューを付けます。

テキストの表示 - インコのWindowsSDK で作成したソースを修正します。

ここでは、Reseditで作成する方法も説明します。

流れ

ツリービューは、コモンコントロールの一つです。

1.commctrl.hをインクルード。

2.comctl32.lib を読み込みます。

WM_INITDIALOG

WM_INITDIALOGは、ダイアログが作成されたときに一度だけ実行されます。

1.InitCommonControls()でコモンコントロールの初期化。

2.ツリービューを作成します。まずは、TV_INSERTSTRUCT構造体を初期化。構造体にデータをセット。

typedef struct tagTVINSERTSTRUCT {
    HTREEITEM hParent;       // ツリービューのハンドル
    HTREEITEM hInsertAfter;  // 挿入位置を表すアイテムのハンドル
    union
    {
        TVITEMEX itemex;     // 追加するアイテムの情報を指定したTVITEMEX構造体が格納
        TVITEM item;         // 追加するアイテムの情報を指定したTVITEM構造体が格納
    } DUMMYUNIONNAME;
} TVINSERTSTRUCT, *LPTVINSERTSTRUCT;

hInsertAfter説明
TVI_ROOTアイテムをルートアイテムとして追加
TVI_FIRSTアイテムをリストの最初の位置に挿入
TVI_LASTアイテムをリストの最後の位置に挿入
TVI_SORTアイテムをアルファベット順にリストに挿入

ここでは、tv.hInsertAfter = TVI_LAST とします。

ここでは、tv.hParent = TVI_ROOT として、ツリービューのトップであることを指定します。
TVI_ROOTの代わりにNULLでも構いません。

TV_INSERTSTRUCT構造体のitemexメンバであるTVITEM構造体

typedef struct tagTVITEM {
    UINT       mask;           // 有効メンバを示すフラグ
    HTREEITEM  hItem;          // アイテムのハンドル
    UINT       state;          // アイテムの状態・イメージ
    UINT       stateMask;      // state のフラグ
    LPTSTR     pszText;        // アイテムの文字列
    int        cchTextMax;     // アイテムの文字列の長さ
    int        iImage;         // イメージのインデックス(非選択時)
    int        iSelectedImage; // イメージのインデックス(選択時)
    int        cChildren;      // 子アイテムを持つかどうかのフラグ
    LPARAM     lParam;         // アイテムの持つ32ビット値
} TVITEM, *LPTVITEM;

TV_INSERTSTRUCT構造体のitemメンバであるTVITEMEX構造体 : TVITEM構造体にメンバ iIntegral を追加したものです。

typedef struct tagTVITEMEX {
    UINT       mask;           // 有効メンバを示すフラグ
    HTREEITEM  hItem;          // アイテムのハンドル
    UINT       state;          // アイテムの状態・イメージ
    UINT       stateMask;      // state のフラグ
    LPTSTR     pszText;        // アイテムの文字列
    int        cchTextMax;     // アイテムの文字列の長さ
    int        iImage;         // イメージのインデックス(非選択時)
    int        iSelectedImage; // イメージのインデックス(選択時)
    int        cChildren;      // 子アイテムを持つかどうかのフラグ
    LPARAM     lParam;         // アイテムの持つ32ビット値
    int        iIntegral
} TVITEMEX, *LPTVITEMEX;

mask有効メンバを示すフラグ
TVIF_TEXTpszText, cchTextMaxメンバが有効

ここでは、TVITEM構造体を使い、tv.item.mask = TVIF_TEXT とします。

tv.item.pszText = TEXT("親1") というように、アイテムをセットしていきます。

3.TreeView_InsertItem()ツリービューの親項目や子項目を追加します。

HTREEITEM TreeView_InsertItem(
    HWND hwndTV,           // ツリービューのハンドル
    LPTVINSERTSTRUCT lpis  // 追加するTV_INSERTSTRUCT構造体のポインタ
);

戻り値は、追加したツリービュー項目のハンドルになります。

リソースファイル

1.ツリービューを使用するため、commctrl.hをインクルード。

2.ツリービュー[WC_TREEVIEW]を追加。

WC_TREEVIEWの代わりに、"SysTreeView32"と記述することができます。「" "」を忘れないで下さい。
この場合は、リソースファイルで、commctrl.hをインクルードする必要はありません。
ただし、"SysTreeView32"と記述した場合でも、Cソースファイルでは、commctrl.hのインクルードが必要です。

CONTROL  "", id, WC_TREEVIEW, style, x0, y0, width, height

idツリービューID
styleツリービューのスタイル
ウインドウスタイルと、ツリービューのスタイルが指定可能
x0ツリービュー左上のx座標
y0ツリービュー左上のy座標
widthツリービューの幅
heightツリービューの高さ

・Visual Studioのリソース ビュー、ResEditでの設定
ツールボックス(Toolbox)ウインドウの「TreeView Cntrol」を選択

ResEditツールボックス1

プロパティは、
・Has Buttons (TVS_HASBUTTONS : 子アイテムを持つときに親アイテムの横に + や - を表示 )、
・Has Lines (TVS_HASLINES : アイテムをつなぐ線を表示)、
・Lines At Root (TVS_LINESATROOT : 一番上のアイテムの線を表示)、
・Scroll (TVS_NOSCROLL : スクロールなし。スクロールバー非表示)
をすべてtrueにします。

ResEditツールボックス2

ソースコードの入力

ソースコードは下記のように入れてください。

test.cpp
#include <windows.h>
#include <commctrl.h>
#include "resource.h"

#pragma comment(lib, "comctl32.lib")

// このコード モジュールに含まれる関数の宣言を転送します:
BOOL CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
          PSTR lpCmdLine, int nCmdShow )
{
    DialogBox(hInstance, TEXT("DIALOG_BOX"), NULL, DialogProc);
    return 0;
}

BOOL CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HTREEITEM hParent1, hParent2, hParent3, hChild1, hChild2;
    TV_INSERTSTRUCT tv;
    switch (msg)
    {
        case WM_INITDIALOG:
            InitCommonControls(); 

            memset(LPTSTR(&tv), '\0', sizeof(tv));

            tv.hInsertAfter = TVI_LAST;
            tv.item.mask = TVIF_TEXT;
            tv.hParent = TVI_ROOT;
            tv.item.pszText = TEXT("親1");
            hParent1 = TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);

            tv.item.pszText = TEXT("親2");
            hParent2 = TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);

            tv.item.pszText = TEXT("親3");
            hParent3 = TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);

            tv.hParent = hParent1;
            tv.item.pszText = TEXT("子1");
            hChild1 = TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);
            tv.item.pszText = TEXT("子2");
            hChild2 = TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);
            tv.hParent = hChild1;
            tv.item.pszText = TEXT("孫1");
            TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);
            tv.hParent = hChild1;
            tv.item.pszText = TEXT("孫2");
            TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);
            tv.hParent = hParent2;
            tv.item.pszText = TEXT("子3");
            TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);
            tv.hParent = hParent3;
            tv.item.pszText = TEXT("子4");
            TreeView_InsertItem(GetDlgItem(hWnd,IDC_TREE1), &tv);
            break;
        case WM_CLOSE:
            EndDialog(hWnd, IDOK);
            break;
        default:
            break;
    }
    return FALSE;
}

resource.h

#define IDC_TREE1 1011
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif

Reseditで作成した場合は、これとは異なるソースコードになります。
上記の太線で示している箇所のみ追加です。

test.rc

#include <windows.h>
#include <commctrl.h>
#include "resource.h"

/////////////////////////////////////////////////////////////////////////////
//
// ダイアログ
//

DIALOG_BOX DIALOG 0, 0, 170, 62
FONT 9, "MS UI Gothic"
CAPTION "ダイアログ"
BEGIN
    CONTROL         "", IDC_TREE1, WC_TREEVIEW,
    WS_TABSTOP | WS_BORDER | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_INFOTIP,
    1, 1, 168, 60
END

Reseditで作成した場合は、これとは異なるソースコードになります。
上記の太線で示している箇所のみ追加です。