ツリービュー(CTreeCtrlクラス)の基本的な使い方について説明します。
開発環境 | Visual Studio 2022 |
---|---|
言語 | C++ |
フレームワーク | MFC |
動作確認 | Windows 11 Windows 10 Windows 7 |

前提条件
- ツールボックスより、「Tree Control」をダイアログに貼ります。
- ダイアログクラスにメンバー変数を追加します。
CTreeCtrl m_tree;
DDX_Control(pDX, IDC_TREE1, m_tree);
プロパティ
- アイテムの親子関係を線で結ぶには、「行あり」「ルートの行」をTrueに設定します。(「行」は「線」の誤訳と思われます。原語はlines)
- 親アイテムの横にプラス/マイナスボタンを表示するには、「ボタンあり」「ルートの行」をTrueに設定します。
- 線とボタンの両方を表示するには、「行あり」「ボタンあり」「ルートの行」をTrueに設定します。



アイテムの追加
各アイテムは、一意のハンドルにて識別されます。また、テキストの文字コードは、UTF-16です。
// ルート
HTREEITEM ハンドル = m_tree.InsertItem(テキスト);
// ルート以外
HTREEITEM ハンドル = m_tree.InsertItem(テキスト, 親アイテムのハンドル);
// 例
HTREEITEM hItem_1 = m_tree.InsertItem(L"東京都");
HTREEITEM hItem_2 = m_tree.InsertItem(L"新宿区", hItem_1);
HTREEITEM hItem_3 = m_tree.InsertItem(L"西新宿", hItem_2);
上記の方法では、親アイテムに対して複数の子アイテムを追加する際、末尾に追加されます。先頭に挿入するには、3番目の引数にTVI_FIRSTを設定します。また、ソートしながら追加したい場合は、3番目の引数にTVI_SORTを設定します。ただし、ソートされるのはTVI_SORTを設定したアイテムのみです。既にTVI_LAST(デフォルト値)/TVI_FIRSTにて追加されたアイテムは、ソートされません。
// 「追加方法」は、TVI_LAST、TVI_FIRST、TVI_SORTのいずれか
// ルート
HTREEITEM ハンドル = m_tree.InsertItem(テキスト, TVI_ROOT, 追加方法);
// ルート以外
HTREEITEM ハンドル = m_tree.InsertItem(テキスト, 親アイテムのハンドル, 追加方法);
追加後に子アイテムをまとめてソートするには、SortChildrenを使用します。この場合、TVI_LAST/TVI_FIRST/TVI_SORTの指定は関係ありません。ただし、ソート対象は、親アイテム直下の子アイテムのみです(孫アイテムは対象外)。
// ソート対象はルート
m_tree.SortChildren(TVI_ROOT);
// ソート対象はルート以外
m_tree.SortChildren(親アイテムのハンドル);
選択したアイテムの取得
(1) ダイアログクラスにメンバー関数を追加します。(関数名は任意)
void OnTreeSelChanged(NMHDR *, LRESULT *);
(2) メッセージマップに、以下を追加します。
ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, OnTreeSelChanged)
(3) メンバー関数を記述します。ツリービューにメッセージが飛ぶ(マウスや矢印キーでアイテム選択)度に、この関数が呼ばれます。
void CXxxxDlg::OnTreeSelChanged(NMHDR *, LRESULT *)
{
// ハンドルの取得
HTREEITEM hItem = m_tree.GetSelectedItem();
if (hItem != nullptr)
{
// テキストの取得
std::wstring name = m_tree.GetItemText(hItem);
// 階層の取得
int level = 0;
HTREEITEM hTemp = hItem;
do
{
level++;
// 親アイテムのハンドルを取得。引数がルートのハンドルの場合、nullptrが返る
hTemp = m_tree.GetParentItem(hTemp);
}
while (hTemp != nullptr);
// hItem ハンドル
// name テキスト
// level 階層(1開始)
}
}
アイテムの削除
// ハンドルに該当するアイテムを削除。子アイテムが存在する場合は、同時に削除される
m_tree.DeleteItem(ハンドル);
// 全削除
m_tree.DeleteAllItems();
サンプルソース
指定したフォルダーの配下を再帰的に検索して、全フォルダー/ファイル名をツリービューに追加します。<filesystem>を使用するので、プロジェクトのプロパティにて、[全般]-[C++言語標準]に「ISO C++17標準(/std:c++17)」以降を選択します。
#include <filesystem>
// 呼び出し側
std::filesystem::path p = L"フォルダーのフルパス、あるいはカレントフォルダーからの相対パス";
// ルートに設定
HTREEITEM hItem = m_tree.InsertItem(p.filename().c_str());
recursive(hItem, p);
// ダイアログクラスに再帰検索用のメンバー関数を追加(関数名は任意)
void CXxxxDlg::recursive(const HTREEITEM &hItem, const std::filesystem::path &p)
{
for (const std::filesystem::directory_entry &i : std::filesystem::directory_iterator(p))
{
if (i.is_directory())
{
// フォルダー
HTREEITEM hNewItem = m_tree.InsertItem(i.path().filename().c_str(), hItem);
// 再帰呼び出し
recursive(hNewItem, i.path());
}
else if (i.is_regular_file())
{
// ファイル
m_tree.InsertItem(i.path().filename().c_str(), hItem);
}
}
}
リファレンス
CTreeCtrl Class
https://learn.microsoft.com/en-us/cpp/mfc/reference/ctreectrl-class