TreeViewの子ノード取得

タグの編集
投稿者 neptune  (社会人) 投稿日時 2008/10/3 08:10:35
こんにちは

質問させて下さい。

質問は表題の通りですが、TreeViewの任意のNodeの子Node(TreeNode)を取得したいのですが
どうも見当たりません。MSDNでは確認してます。Webも検索したんですが見当たりません。

VB6にはchildプロパティ、APIにもそれようのMessageがあるのに、VB2008では無いようです。
兄弟ノード、親ノードは取得できるようなのに子ノード用はホントに用意されてないのでしょうか?

無い場合は、やはり力任せにTreeNodeCollectionなどを使用して1つ1つ
検査するしかないのでしょうか?・・・・なんか不細工な気がするんですが。。。

探し方が悪いのかもしれませんが、ご教示お願いします。
投稿者 よねKEN  (社会人) 投稿日時 2008/10/3 08:37:59
> TreeViewの任意のNodeの子Node(TreeNode)を取得したいのですが

任意のNodeのどの子Nodeを取得したいのでしょう?(通常、子Nodeは複数ありますが)

> VB6にはchildプロパティ

Childプロパティは使ったことがありませんが、検索して調べた感じでは、
最初の子ということであってますか?
それなら、TreeNodeクラスのFirstNodeプロパティが該当します。

そうでない場合でも、似た系統であるNodeを取得できるプロパティとしてはTreeNodeクラスの
LastNode、NextNode、NextVisibleNode、Parent、PrevNode、PrevVisibleNode 
がありますので、この中に該当するものがないかもMSDNライブラリで説明を見て確認してください。
TreeView.TopNodeプロパティというのもありますね。

#機能の実装例を示して、こういうのないですか?と質問するときは、
#その機能の説明も合わせて行っていただけると
#その例を知らなくてもよいので助かります。

> 無い場合は、やはり力任せにTreeNodeCollectionなどを使用して1つ1つ
> 検査するしかないのでしょうか?・・・・なんか不細工な気がするんですが。。。

これを見ると何らかの条件に合致するNodeを検索したいのでしょうか?
座標指定でなら、TreeView.GetNodeAtや、
TreeNodeインスタンスの参照を持っていてそのノードを探したいなら、
TreeNodeCollectionのFindメソッドを使うとか、
状況に応じていろいろな機能がありますが、使えませんか?

投稿者 neptune  (社会人) 投稿日時 2008/10/3 22:49:41
こんにちは


よねKEN さん
アドバイスありがとうございます。
曖昧な質問の仕方ですみませんでした。
少し長くなりますが、もっと詳細に書いておきます。


●動機:
私は、複雑なコントロールに慣れようとする時は簡単なサンプルを作って慣れるのですが、
TreeView、ListViewの場合はこのサイトでも採用しておられるようにエクスプローラ
もどきを作ります。何かで使いまわしも出来るかもしれないし。

今回はラッキーにも「初級講座 第25回 実技2 フォルダ情報一覧」が目的に
ぴったりなので講座のソースも利用させていただいてます。

●何に使うか:
で、全てのノード(全てのフォルダ)を最初からTreeViewに追加すると無駄に重いので
子フォルダの存在を示す「+」マーク対策としてノード展開前に
・孫ノードが存在するかどうか確認
・なければ、そのパスをチェックしフォルダがあれば孫ノードとして追加
 →展開時新たに表示されるノードに「+」が表示される
という方法を取っています。


1 □
2  -□
3    -□
4    -□
5    -□
6      -□
7      -□
8      -□

●やりたい事:
例えば上図の1~5の任意のノードの子ノード(できれば子ノードの最初のもの)を取得したい

●目的:
取得した子ノードが更に子ノードを持っているかどうかを確認したい。子ノードが取れれば
その兄弟ノードは取得できると思うので、最初に取得するノードはどれでも良い。


●FirstNode:
MSDNを見るとそのように書いてますね。。。
FirstNodeも含めてMSDNも何度も見ていたんですが、見方が足りなかったようです。


どうもありがとうございました。お騒がせしました。
検証後又書き込みます。


ところでFindですが、今はまだやってないのですが、検索も考えています。
これも作っておけば役に立つかもしれない。。。


#愚痴ですが、APIでもTVM_GETNEXTITEMのフラグにTVGN_CHILDってのがあるし、
VBもChild プロパティってchildが付いている同じ機能のものがあるのに、
新バージョンの同じ機能でなんでFirstNodeなんや!firstchildnodeやろ!と思ってしまいます。^ ^;
投稿者 よねKEN  (社会人) 投稿日時 2008/10/4 01:48:06
質問のポイントには影響なさそうですが、「何に使うか」の意図の部分が
きちんと理解できていないので、確認させてください。

> ●何に使うか:
> で、全てのノード(全てのフォルダ)を最初からTreeViewに追加すると無駄に重いので
> 子フォルダの存在を示す「+」マーク対策としてノード展開前に
> ・孫ノードが存在するかどうか確認
> ・なければ、そのパスをチェックしフォルダがあれば孫ノードとして追加
>  →展開時新たに表示されるノードに「+」が表示される
> という方法を取っています。

孫ノードの存在確認なら、子ノードのNodes.Countを見るだけでOKだと思うので、
任意の孫ノードを取得したい、というのがよくわかりませんでした。

> MSDNを見るとそのように書いてますね。。。
> FirstNodeも含めてMSDNも何度も見ていたんですが、見方が足りなかったようです。

TreeNodeはNodesプロパティを持っていますが、これの0番目が最初の子です。
なので、Nodes.Countでノード数を確認した上で、1つ以上あれば、
Nodes[0]が最初の子ということになります。

子ノードがない場合はFirstNodeはNothingなので使用する前に
Nothingでないかどうかのチェックが必要です。
そういう意味では、Nodes[0]を使うのもFirstNodeを使うのも使い勝手に差はありません。
最初のノードだよとわかりやすくする意味では、Nodes[0]を使うよりFirstNodeの方が
可読性の点ではよいと思います。

FirstNodeを使う場合の処理のパターンとしては、

(1)FirstNodeを現在のノードにセットする。
(2)現在のノードに対する処理をする。
(3)現在のノードのNextNodeを取得し、現在のノードにセットする。
(4) 現在のノードがNothingなら終了、そうでなければ(2)、(3)を繰り返し。

のように使うことになると思っていますが、
これはNodesプロパティから順にノードを列挙し、それに処理をするのと同じで、
私はこちらの方の処理を多く使いますね。

FirstNode/LastNodeNextNode/PrevNodeを使うのは、
ユーザが選択したノードを基準にしてその兄弟ノードの操作をしたいときくらいです。

> 新バージョンの同じ機能でなんでFirstNodeなんや!firstchildnodeやろ!と思ってしまいます。^ ^; 

子ノードではないからでしょうね。
ある階層のノード同士の中で「最初の」ノードだからです。
例えば、TreeView.Nodesに同階層で2つのノードだけを追加した状態では、
1つ目がFirstNode、2つ目がLastNodeになるかと思いますが、これらルートなので子ノードではありませんね。

今までの命名が理路整然とされていなかったから、その点は改善されたということだと思っています。
投稿者 neptune  (社会人) 投稿日時 2008/10/4 07:19:44
よねKEN さん

続けてアドバイスありがとうございます。

>孫ノードの存在確認なら、子ノードのNodes.Countを見るだけでOKだと思うので、
>任意の孫ノードを取得したい、というのがよくわかりませんでした。
Nodes.Countを思いつきませんでした。

結局こうなりました。
>FirstNodeを使う場合の処理のパターンとしては、
の予想どおりですね。

    
  '勉強中の方々への参考:初級講座 第25回 実技2 フォルダ情報一覧」 
  'これは多分 tvFolders_AfterSelect の代わりになります。 
    '興味があれば試してみて下さい。手直しがあればして下さいね。 
    Private Sub TreeView1_BeforeExpand(ByVal sender As ObjectByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles TreeView1.BeforeExpand
        Dim tn As TreeNode = e.Node.FirstNode()     '子ノードの先頭取得 

        'ノードの数だけ実行 
        For i As Integer = 0 To e.Node.Nodes.Count - 1
            If Not tn Is Nothing Then
                Dim dirinfo As DirectoryInfo = New DirectoryInfo(tn.FullPath)
                Try
                    If dirinfo.GetDirectories().Count > 0 Then
                        '子ノードを追加する 
                        AddChildNodes(tn)  '講座の中のAddSubNodesと同じ処理です。 
                    End If
                    Console.WriteLine(tn.Text)
                Catch ex As Exception

                End Try
            End If
            tn = tn.NextNode()
        Next
    End Sub

>これはNodesプロパティから順にノードを列挙し、それに処理をするのと同じで、
 そう言えばそうですね。
 
>> 新バージョンの同じ機能でなんでFirstNodeなんや!firstchildnodeやろ!と思ってしまいます。^ ^; 
>ある階層のノード同士の中で「最初の」ノードだからです。
>今までの命名が理路整然とされていなかったから、その点は改善されたということだと思っています。
確かにその通りではありますが、いわゆる慣れっていう奴の直感が通用しないので、
MSDNを読む時は隅々までよく読めって教訓になったような気がします。

尤も、よく読んでも判らんもんが多いですが。

今回はTreeViewに付いて思い浮かばなかった方法も含め勉強になりました。
ちょっとTreeVieに付いての理解が進んだような気がします。
どうもありがとうございました。
投稿者 neptune  (社会人) 投稿日時 2008/10/4 07:22:54
続けてすみません。書き忘れ。
tvFolders_AfterSelectの代わりになるって書いてしまいましたが、
それには初期状態として、各ドライブの直下のディレクトリはあらかじめ追加しておく
必要があります。