VC CTreeCtrlの選択されたアイテムを起点に検索する
はじめに
CTreeCtrlのItemを選択されたところから検索したいなと思いました。
イメージとしてはレジストリエディタの検索みたいな感じです。
次へとやると選択されたところから下を探して、親をたどって下まで行ったらまた戻ってくるみたいな。
とまー、ツリーと言えば再帰で書けば楽勝でしょ…
と安直に思ったんです。
そしたら、すごいはまってしまったんですね。
検索するときに使うCTreeCtrlのメソッド
HTREEITEMをCTreeCtrlに渡して値の取得や親子兄弟を取得します。
基本、下の関数だけあれば検索できると思います。
HTREEITEM GetRootItem()
-> ツリーのルートアイテムを取得する
HTREEITEM GetSelectedItem()
-> 現在選択されているアイテムを取得する
CString GetItemText(HTREEITEM)
-> HTREEITEMのラベルを取得する
DWORD_PTR GetItemData(HTREEITEM)
-> HTREEITEMのデータを取得する
HTREEITEM GetChildItem(HTREEITEM)
-> HTREEITEMの子を取得する
HTREEITEM GetNextSiblingItem(HTREEITEM)
-> HTREEITEMの兄弟を取得する
HTREEITEM GetParentItem(HTREEITEM)
-> HTREEITEMの親を取得する
しかし、この親子兄弟関係、1個ずつしか取れないのです。
けっこう癖がありますね…
処理説明
自分と兄弟から下のノードとリーフに対して処理を行う。
終わったら、親の取得を行っていく。
処理対象は親の兄弟から。
以降、じいちゃん、ひいじいちゃんと確認していく。
呼び側
現在選択位置から検索して、S_FALSEだったら再度
ルートから検索するようにする。
HRESULT XXXXX::FindItem(HTREEITEM hItem, CString KeyWord, bool bParentSearch)
{
HRESULT result = S_FALSE;
if (hItem == NULL) { return S_FALSE; }
HTREEITEM hSibling = hItem;
while (hSibling != NULL)
{
//
// 検索処理などstart
// ここでは、KeyWordのラベルなら選択状態にする
// DWORD_PTR dword = m_pTreeCtrl->GetItemData(hSibling);
CString itemLabel = m_pTreeCtrl->GetItemText(hSibling);
if (itemLabel == KeyWord && hSibling != m_pTreeCtrl->GetSelectedItem())
{
m_pTreeCtrl->SelectItem(hSibling);
m_pTreeCtrl->DoProperActions(true);
return S_OK; // <-終わったらS_OKで戻す
}
// 検索処理などend
//
// 子を処理する
HTREEITEM hChild = m_pTreeCtrl->GetChildItem(hSibling);
if (hChild == m_pTreeCtrl->GetSelectedItem()) { return E_FAIL; }
result = FindItem(hChild, KeyWord, false);
if (result != S_FALSE) { return result; }
// 兄弟を処理する
hSibling = m_pTreeCtrl->GetNextSiblingItem(hSibling);
if (hSibling == m_pTreeCtrl->GetSelectedItem()) { return E_FAIL; }
}
if (bParentSearch)
{
// 自分の親を取得する
HTREEITEM hParent = m_pTreeCtrl->GetParentItem(hItem);
while (hParent != NULL)
{
HTREEITEM hParentSibling = hParent;
while (hParentSibling != NULL)
{
// 自分の親は処理せず親の弟妹を処理する
// 兄姉は処理しない
hParentSibling = m_pTreeCtrl->GetNextSiblingItem(hParentSibling);
if (hParent == m_pTreeCtrl->GetSelectedItem()) { return E_FAIL; }
// 末っ子の確認末っ子なら、親探しフラグをたてる
HTREEITEM terminat = m_pTreeCtrl->GetNextSiblingItem(hParentSibling);
result = FindItem(hParentSibling, KeyWord, bParentSearch && terminat == NULL);
if (result != S_FALSE) { return result; }
}
// 自分の親のじいちゃんを取得する
hParent = m_pTreeCtrl->GetParentItem(hParent);
}
}
return result;
}
HRESULT result = FindItem(m_pTreeCtrl->GetSelectedItem(), KeyWord, true);
if (result == S_FALSE)
{
result = FindItem(m_pTreeCtrl->GetRootItem(), KeyWord, false);
}
終わりに
ルートからだけなら、1個目のwhileだけで事足りそうですね。
これに、先代を遡るとややこしくなってきました。
自分がはまったポイントです…
もう少し簡単に書けそうな気がしたのですが、自分はこれが限界の様です…