tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルTreeViewのノードの保存
記事No14888
投稿日: 2010/09/02(Thu) 10:07
投稿者ima
WinXP VB6 sp6

TreeViewを使って階層構造のシソーラス辞書の様な物を作成中です。

現状、リストボックスなどのキーワード群からDrag & Dropで
TreeViewに取り込んだり、TreeView内でDrag & Dropにて階層を
上下に移動させたり、ノードの削除まで実装できています。


このノード全体(階層構造)を、画面に表示されている順で保存したい
のです。 → 順序自体に意味がある

しかし、下記のコードでは、各ノード作成時のインデックス順?
にリストアップされるためか、ノードの位置を上下に移動させた
状況が反映されません。

    For Each nod In TreeView1.Nodes
        Debug.Print nod.Text
    Next


画面に表示されている順、そのままでリストアップするには
どうすればよいでしょうか?

よろしくお願いします。

[ツリー表示へ]
タイトルRe: TreeViewのノードの保存
記事No14889
投稿日: 2010/09/02(Thu) 12:11
投稿者魔界の仮面弁士
# コード修正

> 画面に表示されている順、そのままでリストアップするには
> どうすればよいでしょうか?

For Each で列挙するのではなく、各ノードの親子兄弟関係を元に Loop 処理しましょう。
基本的には、Next と Child を再起処理すれば列挙できるはずです。

          Root プロパティ:最上位ノードを返す(最上位が複数いる場合はその中の長兄)
        Parent プロパティ:    親ノードを返す(自身が最上位ノードの場合は Nothing)
      Previous プロパティ:  兄者ノードを返す(自身が長兄の場合は Nothing)
          Next プロパティ:  弟者ノードを返す(自身が末弟の場合は Nothing)
  FirstSibling プロパティ:  長兄ノードを返す(自身が長兄の場合は自ノード)
   LastSibling プロパティ:  末弟ノードを返す(自身が末弟の場合は自ノード)
         Child プロパティ:  長子ノードを返す(子が居ない場合は Nothing)

なお Root プロパティだけは、自身の階層位置とは無関係です。


Option Explicit

Private Sub Form_Load()
    List1.Font.Name = "MS ゴシック"
    List1.Font.Size = 12
  
    Dim d As Collection
    Set d = New Collection
    
    d.Add TreeView1.Nodes.Add(Key:="N1", Text:="N1"), "N1"
    d.Add TreeView1.Nodes.Add(Key:="N2", Text:="N2"), "N2"
    d.Add TreeView1.Nodes.Add(Key:="N3", Text:="N3"), "N3"
    d.Add TreeView1.Nodes.Add(Key:="N4", Text:="N4"), "N4"
    d.Add TreeView1.Nodes.Add(Key:="N1-1", Text:="N1-1"), "N1-1"
    d.Add TreeView1.Nodes.Add(Key:="N1-2", Text:="N1-2"), "N1-2"
    d.Add TreeView1.Nodes.Add(Key:="N1-3", Text:="N1-3"), "N1-3"
    d.Add TreeView1.Nodes.Add(Key:="N1-4", Text:="N1-4"), "N1-4"
    d.Add TreeView1.Nodes.Add(Key:="N3-1", Text:="N3-1"), "N3-1"
    d.Add TreeView1.Nodes.Add(Key:="N1-2-1", Text:="N1-2-1"), "N1-2-1"
    d.Add TreeView1.Nodes.Add(Key:="N1-2-2", Text:="N1-2-2"), "N1-2-2"
    d.Add TreeView1.Nodes.Add(Key:="N1-4-1", Text:="N1-4-1"), "N1-4-1"
    
    Set d("N1-4").Parent = d("N1")
    Set d("N1-3").Parent = d("N1")
    Set d("N1-2").Parent = d("N1")
    Set d("N1-1").Parent = d("N1")
    
    Set d("N3-1").Parent = d("N3")
    
    Set d("N1-2-2").Parent = d("N1-2")
    Set d("N1-2-1").Parent = d("N1-2")
    
    Set d("N1-4-1").Parent = d("N1-4")
    
    TreeView1_NodeClick d(1)
End Sub

Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
    List1.Clear
    If Node Is Nothing Then Exit Sub
    List1.AddItem "        Root - " & GetText(Node.Root)
    List1.AddItem "      Parent - " & GetText(Node.Parent)
    List1.AddItem "    Previous - " & GetText(Node.Previous)
    List1.AddItem "        Next - " & GetText(Node.Next)
    List1.AddItem "FirstSibling - " & GetText(Node.FirstSibling)
    List1.AddItem " LastSibling - " & GetText(Node.LastSibling)
    List1.AddItem "       Child - " & GetText(Node.Child)
End Sub

Function GetText(ByVal n As Node) As String
    If n Is Nothing Then
        GetText = "(nothing)"
    Else
        GetText = n.Key
    End If
End Function

Sub DumpNextNode(ByVal target As Node, ByVal level As Integer)
    If target Is Nothing Then
        Exit Sub
    Else
        Debug.Print Tab(level); target.Key
    End If
    DumpNextNode target.Child, level + 1
  DumpNextNode target.Next, level
End Sub

Private Sub Command1_Click()
    If TreeView1.Nodes.Count = 0 Then
        Exit Sub
    Else
        Debug.Print "----"
        DumpNextNode TreeView1.Nodes(1).Root, 1
    End If
End Sub

[ツリー表示へ]
タイトルRe^2: TreeViewのノードの保存
記事No14890
投稿日: 2010/09/02(Thu) 13:14
投稿者ima
魔界の仮面弁士さん、いつも素早い回答で感謝します。
私の中に組み込んだ場合、ご呈示いただいたコードでは、
なぜか最初では良さそうでしたが、再帰が上手く行かなかったのか
不必要に繰り返しが有りました。

> Function GetText(ByVal n As Node) As String
>     If n Is Nothing Then
>         GetText = "(nothing)"
>     Else
>         GetText = n.Key
>     End If
> End Function
>
> Sub DumpNextNode(ByVal target As Node, ByVal level As Integer)
>     If target Is Nothing Then
>         Exit Sub
>     Else
>         Debug.Print Tab(level); target.Key
>     End If
>     DumpNextNode target.Child, level + 1
>    
>     Dim n As Node
>     Set n = target.Next
>     Do Until n Is Nothing
>         DumpNextNode n, level
>         Set n = n.Next
>     Loop
> End Sub
>
> Private Sub Command1_Click()
>     If TreeView1.Nodes.Count = 0 Then
>         Exit Sub
>     Else
>         Debug.Print "----"
>         DumpNextNode TreeView1.Nodes(1).Root, 1
>     End If
> End Sub

私なりにヘルプを参考に作ったコードです。

'TreeViewの見たまま書き出し
Private Sub Command2_Click()
Dim objNode As Node, strText As String, lNodeDepth As Long
    Set objNode = TreeView1.Nodes.Item(1).FirstSibling.Child
    Call DumpNextNode(objNode, strText, lNodeDepth)
    Debug.Print strText    ' 結果を表示
End Sub

Private Sub DumpNextNode(ByVal BaseNode As Node, strText As String, lNodeDepth As Long)
Dim n As Long
Dim objNode As Node
    If Not BaseNode Is Nothing Then
        '変数 n に先頭項目のインデックスを代入
        n = BaseNode.FirstSibling.Index
        '文字列変数に先頭項目のテキストおよび改行を代入
        strText = strText & String(lNodeDepth, vbTab) & BaseNode.FirstSibling.Text & vbLf
        While n <> BaseNode.LastSibling.Index
            If TreeView1.Nodes(n).children > 0 Then
                Set objNode = TreeView1.Nodes(n).Child.FirstSibling
                Call DumpNextNode(objNode, strText, lNodeDepth + 1)
            End If
            'n が末尾項目のインデックスになるまで、次の項目に進み、
            'そのテキストを文字列変数に入れます。
            strText = strText & String(lNodeDepth, vbTab) & TreeView1.Nodes(n).Next.Text & vbLf
            '変数 n に次のノードのインデックスを代入します。
            n = TreeView1.Nodes(n).Next.Index
        Wend
    End If
End Sub

とりあえず、希望の形式で出力できましたがおかしな所も有るかも知れません。

今回も色々勉強させていただきました。
有り難うございました。

[ツリー表示へ]
タイトルRe^3: TreeViewのノードの保存
記事No14891
投稿日: 2010/09/02(Thu) 14:20
投稿者魔界の仮面弁士
ごめんなさい。訂正前のコードを貼ってしまいました。

> 不必要に繰り返しが有りました。
その通り、ループ処理が不必要です。
修正版に差し替えておきましたので、 No.14889 を再確認してみてください。


> とりあえず、希望の形式で出力できましたがおかしな所も有るかも知れません。
その実装だと、たとえば下記の場合、最後の Text1-2-1 が列挙されませんよ。

Private Sub Form_Load()
    TreeView1.Nodes.Add(, , "Key1", "Text1").Expanded = True
    TreeView1.Nodes.Add("Key1", tvwChild, "Key1-1", "Text1-1").Expanded = True
    TreeView1.Nodes.Add("Key1", tvwChild, "Key1-2", "Text1-2").Expanded = True
    TreeView1.Nodes.Add("Key1-1", tvwChild, "Key1-1-1", "Text1-1-1").Expanded = True
    TreeView1.Nodes.Add("Key1-1", tvwChild, "Key1-1-2", "Text1-1-2").Expanded = True
    TreeView1.Nodes.Add("Key1-2", tvwChild, "Key1-2-1", "Text1-2-1").Expanded = True
End Sub


> Private Sub Command2_Click()
> Dim objNode As Node, strText As String, lNodeDepth As Long
>     Set objNode = TreeView1.Nodes.Item(1).FirstSibling.Child
この方法は、.Item(1) の階層位置が固定的な場合にしか利用できません。

たとえば、
 【ア】.Nodes(n).Root.FirstSibling.Child
 【イ】.Nodes(n).Root.Child
 【ウ】.Nodes(1).FirstSibling.Child
とあった場合、アとイは常に「最上位先頭ノードの第一子」を示しますが、
ウの結果は 第2階層になることもあれば第4階層になることもありえます。

[ツリー表示へ]
タイトルRe^4: TreeViewのノードの保存
記事No14896
投稿日: 2010/09/03(Fri) 07:37
投稿者ima
> ごめんなさい。訂正前のコードを貼ってしまいました。

 有り難うございます。しっかり希望の動作することを確認しました。
 

> > とりあえず、希望の形式で出力できましたがおかしな所も有るかも知れません。
> その実装だと、たとえば下記の場合、最後の Text1-2-1 が列挙されませんよ。

 そうですね!気が付きませんでした。

> > Private Sub Command2_Click()
> > Dim objNode As Node, strText As String, lNodeDepth As Long
> >     Set objNode = TreeView1.Nodes.Item(1).FirstSibling.Child
> この方法は、.Item(1) の階層位置が固定的な場合にしか利用できません。
>
> たとえば、
>  【ア】.Nodes(n).Root.FirstSibling.Child
>  【イ】.Nodes(n).Root.Child
>  【ウ】.Nodes(1).FirstSibling.Child
> とあった場合、アとイは常に「最上位先頭ノードの第一子」を示しますが、
> ウの結果は 第2階層になることもあれば第4階層になることもありえます。

 .Item(1)が別の(下位)階層に移動した場合と言うことでしょうか?
 その階層の先頭となるのでしょうかね? → Indexは固定のため?

私のコードの修正は後日行うとして、とりあえず解決とさせていただきます。

色々詳しい解説、感謝いたします。

[ツリー表示へ]