Version 8.12
ツリーアイテム
「前回に引き続き、ツリービューコントロールについて見ていきます」
『この前はアイテムの追加をしたんだよね』
「今回もそう。まず復習から」
BOOL CMfcDialogDlg::OnInitDialog()
{
// 略。
// TODO: 特別な初期化を行う時はこの場所に追加してください。
HTREEITEM hParentItem
= m_cMainTree.InsertItem( "1番目のアイテム" );
m_cMainTree.InsertItem( "2番目のアイテム", hParentItem );
return TRUE;
}
『 CTreeCtrl::InsertItem() でアイテム追加、第2引数を省略すると親と
して追加されて、そこにアイテムのハンドルを渡すとその子アイテムとして
追加される、と』
「そゆこと。第2引数を省略すると TVI_ROOT が渡されて、これが親アイテ
ムとして追加、って指定になるから」
『ってことは、』
m_cMainTree.InsertItem( "1番目のアイテム", TVI_ROOT );
『でも親アイテムとして追加できるわけね。そういえば、第3引数も省略さ
れてたけど、あれは?』
「第3引数では〈どの子アイテムの下に入れるか〉を指定します」
『?』
「んー、第2引数は親子関係、ツリービューコントロールで言えば〈横〉の
関係を変えるものだったけど、第3引数は〈縦〉の関係を変えるもの」
『あー、そういう意味で〈下に〉ってことね』
「ま、実際に見てもらった方がいいかも」
BOOL CMfcDialogDlg::OnInitDialog()
{
// 略。
// TODO: 特別な初期化を行う時はこの場所に追加してください。
HTREEITEM h1stItem
= m_cMainTree.InsertItem( "1番目のアイテム" );
m_cMainTree.InsertItem( "3番目のアイテム" );
m_cMainTree.InsertItem( "2番目のアイテム", TVI_ROOT, h1stItem );
return TRUE;
}
『3回目の追加で第3引数に……1回目に追加したアイテムのハンドルを渡
すと……その1回目に追加したアイテムの下にアイテムが挿入される、と』
「これでどこにでも追加できるでしょ」
『一番上に追加するときは?』
「第3引数に TVI_FIRST を渡せばOK。ちなみに省略すると TVI_LAST が
渡されて」
『これは最後に追加されるわけね』
「そゆこと。ここまでやってみてどう?」
『結構簡単だね』
「でしょう。でも、これは MFC だから」
『 MFC 使わないと面倒?』
「そう、面倒。というわけでその方法をこれから説明します」
『げげ!』
「というよりそのためにこの MFC の例を出したんだし」
『そうだったのか……』
「まず、 MFC を使わないでツリービューコントロールにアイテムを追加す
るときには TVM_INSERTITEM ってメッセージを使います」
『最初に TVM_ が付くのがツリービューコントロールのメッセージ?』
「操作する時はね。通知メッセージは」
『 TVN_ !』
「そう。この辺は規則性あるから分かるよね」
『 M か N かってだけだし』
「まーね。で、この TVM_INSERTITEM のリファレンスを見ると」
『 WPAPAM は 0 、 LPTVINSERTSTRUCT ってのを LPARAM に渡してる』
「この LPTVINSERTSTRUCT の中に、追加するアイテムの情報全部を入れて渡
せば、追加できるわけです」
『 MFC 使ったときの、親アイテムとかもこの中に入れるの?』
「そう、この中に全部入れてから渡します。で、実は MFC でもこの
LPTVINSERTSTRUCT を使ってアイテムを追加できます」
『ホントだ、 CTreeCtrl::InsertItem() のオーバーロードしたのの中にそ
れ引数に取るのがある』
「というわけで、このメンバ関数を使ってアイテムを追加するのを目標にし
ます」
『それができれば MFC 使わないで追加できるんだもんね』
「そゆこと。ま、これは結構難しいんで、少しずつ進めていきます」
『難しいの?』
「思いの外ね。でも、 MFC 使わないでこういうことするときの基本が全部
詰まってるから、ちゃんとマスターしてもらいます」
『う』
「じゃ、ひとつひとつ進めていくからね。まず、ツリービューコントロール
のひとつひとつの〈アイテム〉について」
『 CTreeCtrl::InsertItem() で追加したアイテムね』
「アイテムひとつひとつは HTREEITEM ってハンドルで識別します」
『 CTreeCtrl::InsertItem() の戻り値ね。ん? 一度追加したののハンド
ルって取れる?』
「 CTreeCtrl::GetNextItem() で取れるよ」
『選択されてるのとか、親子とか兄弟とか……あー、さっきの上下のは兄弟
なのね』
「一応例見ておこうか」
BOOL CMfcDialogDlg::OnInitDialog()
{
// 略。
// TODO: 特別な初期化を行う時はこの場所に追加してください。
HTREEITEM hParentItem
= m_cMainTree.InsertItem( "親アイテム" );
HTREEITEM hChildItem
= m_cMainTree.InsertItem( "子アイテム", hParentItem );
HTREEITEM hHitItem
= m_cMainTree.GetNextItem( hParentItem, TVGN_CHILD );
TRACE( "%X, %X\n", hChildItem, hHitItem );
// 同じ値。
return TRUE;
}
『親アイテムの下に子アイテムを追加して、
CTreeCtrl::GetNextItem() で、第1引数に親アイテムのハンドルを渡し
て、第2引数に TVGN_CHILD を渡すと、子アイテムのハンドルが返ってくる
と』
「これは子アイテムの取得法だけど、第2引数を色々変えれば」
『いろんなアイテムが取れるわけね』
「で、これで取得できるのはあくまでハンドル」
『どゆこと?』
「たとえばウィンドウハンドルでウィンドウのタイトルを取得するには」
『 GetWindowText() だよね』
「つまり、ハンドルはあくまでハンドル。そのアイテムの情報を取得するに
は」
『ハンドルを渡して関数よばなきゃいけないわけね』
「そゆこと。ツリービューコントロールは CTreeCtrl::GetItem() で取得し
ます」
『 CTreeCtrl::GetItemData() は違うの?』
「それは一部のデータを取得するだけ。そのデータも普通使わないし」
『 CTreeCtrl::GetItemText() って便利そうなのがあるよ?』
「それは MFC だけ。ここでは MFC を使わずに、 TVM_GETITEM メッセージ
と同じ方法で取得できる CTreeCtrl::GetItem() を使います」
『よーするにめんどーってことね』
「まーそれはね。コード見たらもっと嫌になると思うよ」
BOOL CMfcDialogDlg::OnInitDialog()
{
// 略。
// TODO: 特別な初期化を行う時はこの場所に追加してください。
HTREEITEM hParentItem
= m_cMainTree.InsertItem( "アイテム" );
// TVITEM 構造体の初期化。
char pchText[256];
TVITEM stTvItem;
stTvItem.mask = TVIF_TEXT; // 文字列だけ取得。
stTvItem.hItem = hParentItem; // 取得したいアイテム。
stTvItem.pszText = pchText; // 文字列を受け取る配列。
stTvItem.cchTextMax = 255; // そのサイズ。
// 実際に受け取ります。
m_cMainTree.GetItem( &stTvItem );
TRACE( "%s\n", pchText );
// アイテム
return TRUE;
}
『ななな、なんか複雑……』
「まず最初のアイテム追加は分かるよね」
『そりゃまーね。次に文字配列作ってるね』
「今回の例では追加したアイテムの名前を取得するんだけど、その文字列を
入れる文字配列をここで用意します」
『次に TVITEM っての用意してるね。構造体?』
「そう、この構造体が一番難しいところ。ちょっと CTreeCtrl::GetItem()
のリファレンス見てくれる?」
『ほい。 TVITEM 構造体へのポインタを取るんだね、引数に』
「他には?」
『ないよ、引数はひとつ。……あれ? じゃあハンドルは? HTREEITEM は
渡さなくていいの?』
「その指定は TVITEM 、つまり引数の中に入れて渡します」
『あーなるほど』
「戻り値は?」
『 BOOL 、だから成功したか失敗したか、だね。あれ? じゃあそのアイテ
ムの情報ってどう受け取るの?』
「そう、そこがポイント。実は引数の TVITEM で受け取ります」
『……えーっと、整理すると、どのアイテムのを取るのかってのを引数で指
定して、その情報が同じ引数に帰ってくるっていうこと?』
「そゆこと」
『……それって、なんかヤなんだけど……』
「残念ながらそういう仕様なんだよね。これは TVM_GETITEM もそう」
『仕様なら仕方ないよね……えーっと、 TVITEM 構造体の変数に色々入れて
おくのね。 TVITEM::mask ってどういうの?』
「これは〈どのメンバ変数に値を入れてもらうか〉を指定するフラグ。
TVITEM のリファレンスを見てもらうと分かるけど、多くのデータを取れる
ようになってます」
『 state とか stateMask とかいろいろあるね』
「でもいつも全部返すと大変だから、必要なのはどれってことを
TVITEM::mask で指定するわけ」
『今回は文字列だけだから TVIF_TEXT ね。いくつも必要なときはどうする
の?』
「 | 使って」
『あ、ビットフラグね』
「ビットフラグは Version 4.05 ( No.055 ) 参照」
『次の TVITEM::hItem でさっき追加したハンドルを渡してる、ってことは
ここでさっき言ってた〈取るハンドル〉を指定するわけね』
『 TVITEM::pszText はさっきの文字配列へのポインタ渡してるね』
「ウィンドウズはこのポインタを通してアイテムの名前を配列に書き込んで
くれます」
『 TVITEM::cchTextMax は……文字列のサイズ?』
「そう、受け取る文字配列のサイズ。 -1 してあるのははみ出ないよう念の
ため」
『で、最後に CTreeCtrl::GetItem() でデータを取得するわけね』
「そゆこと。と、ちょっと急いじゃったから次回に続く!」
/*
Preview Next Story!
*/
『急いだから続く、ってよく考えるとすごいよね』
「とにかく、火美ちゃんにはしっかりと理解してもらいたいから」
『ねー、今のあたしって世間的にはどのくらいの腕?』
「……」
『ななな、なに? 黙っちゃって』
「……理解してるのとプログラムが書けるのは別だからなぁ……」
『げ! じゃああたしってそんなに??』
「実践的な技術はそれほどかも……」
『というわけで次回』
< Version 8.13 構造体の使い方 >
「につづく!」
『でも、理解しないでプログラムが書けるよりはいいんじゃない?』
「……いいの?」
『うん、いーや』