Struct を TreeView に登録


    string[]    Data=
    {   "1 鈴木", "2 慎吾", "2 和子", "3 あゆみ", "3 優子", "4 まい", 
        "2 ヘンリー", "3 景子", "4 えみ", "4 裕二",
        "3 紀香", "4 菜々子",
        "1 田中", "2 祐希", "3 雅治",
        "1 佐藤", "2 孝雄", "2 エリザベス", "3 さとみ", "0 "
    };

string で定義した構造体 を TreeView に登録します。

前田稔の超初心者のプログラム入門

プロジェクトの説明

  1. string で定義した構造体 を TreeView に登録します。
    空のプロジェクトから TreeView を設定して下さい。
    プロジェクトの作成は TreeView に登録する を参照して下さい。
  2. Data が TreeView に登録する構造体で Idx がそのインデックスです。
    public class MyForm : Form
    {
        private TreeView treeView1;
        string[]    Data=
        {   "1 鈴木", "2 慎吾", "2 和子", "3 あゆみ", "3 優子", "4 まい", 
            "2 ヘンリー", "3 景子", "4 えみ", "4 裕二",
            "3 紀香", "4 菜々子",
            "1 佐藤", "2 孝雄", "2 エリザベス", "3 さとみ", "0 "
        };
        int         Idx;
    
  3. MyForm() でシステムがロードされるときに一度だけ呼び出される MyForm_Load() 関数を登録します。
        public MyForm()
        {
            InitializeComponent();
            Load += new System.EventHandler(MyForm_Load);
        }
    
  4. InitializeComponent() で TreeView を初期化して下さい。
    構造体のサイズに合わせて、ウインドウと TreeView のサイズを調整しています。
        private void InitializeComponent()
        {
            this.treeView1 = new System.Windows.Forms.TreeView();
            this.SuspendLayout();
            this.treeView1.Location = new System.Drawing.Point(12, 12);
            this.treeView1.Name = "treeView1";
            this.treeView1.Size = new System.Drawing.Size(250, 300);
            this.treeView1.TabIndex = 0;
            this.ClientSize = new System.Drawing.Size(280, 320);
            this.Controls.Add(this.treeView1);
            this.Name = "MyForm";
            this.ResumeLayout(false);
        }
    
  5. MyForm_Load() 関数で NodeRoot をパラメータにして Set_TVFunc() 関数を呼び出します。
    '1' は構造体の先頭のレベル番号です。
    関数から戻ると、TreeView に NodeRoot を登録して TopNode を展開します。
        private void MyForm_Load(object sender, System.EventArgs e)
        {
            treeView1.Nodes.Clear();
            TreeNode NodeRoot = new TreeNode("1 Root");
            Idx = 0;
            Set_TVFunc(NodeRoot, '1');
            treeView1.Nodes.Add(NodeRoot);
            treeView1.TopNode.Expand();
        }
    
  6. Data を TreeView に登録する Set_TVFunc() 関数です。
    パラメータで渡された lev とデータに設定されている key の関係を調べて node に登録します。
        // TreeView に登録する再帰関数
        private void Set_TVFunc(TreeNode node, char lev)
        {   char key;
            key = Data[Idx][0];
    //Console.WriteLine("lev=" + lev + "  key=" + key + "  Idx=" + Idx);
            if (key == '0') return;
            if (key == lev)
            {
                node.Nodes.Add(new TreeNode(Data[Idx]));
                Idx++;
                Set_TVFunc(node, lev);
            }
            if (key > lev)  Set_TVFunc(node.LastNode, key);
            // 関数が return すると、ここに制御が戻ります
            if (key == lev) Set_TVFunc(node, lev);
        }
    
  7. 再帰関数に限らず、関数が return すると関数を呼び出した次の位置に制御が戻ります。
    再帰関数の面白い(難しい)ところは、制御が戻る位置が「その関数自身に含まれる」ことです。
    Set_TVFunc() 関数では key == lev になるまで return を待ち続けて、再び Set_TVFunc(node, lev); で関数を呼び直します。

Root を無くす


  1. Root を親として TreeView に登録しましたが、Root を無くして直接 TreeView に登録する方法を考えます。
    TreeView を TreeNode でキャスト出来たら簡単なのですが、許されないようです。
    そこで TreeView をパラメータにする関数と TreeNode をパラメータにする関数を併用することにします。
    詳細はこのページ後部の【NOTE】を参照して下さい。
        Set_TVFunc(TreeView node, char lev)     //lev=1 で呼ばれる
        Set_TVFunc(TreeNode node, char lev)     //lev>1 のとき呼ばれる
    
  2. MyForm_Load() からは treeView1 をパラメータにして Set_TVFunc() 関数を呼び出します。
    treeView1 に直接データが登録されるので、ここでの登録は必要ありません。
        private void MyForm_Load(object sender, System.EventArgs e)
        {
            treeView1.Nodes.Clear();
            Idx = 0;
            Set_TVFunc(treeView1, '1');
            treeView1.TopNode.Expand();
        }
    
  3. lev=1 で呼び出される Set_TVFunc() 関数です。
    key > lev のとき TreeNode をパラメータにする関数を呼び出します。
    このとき node.TopNode を取得して、wk.NextNode で最後に作成した node をパラメータとして渡します。
        // TreeView に登録する関数(lev=1 で呼ばれる)
        private void Set_TVFunc(TreeView node, char lev)
        {   TreeNode wk;
            char     key;
            int      cnt;
            key = Data[Idx][0];
            if (key == '0') return;
            if (key == '1')
            {
                node.Nodes.Add(new TreeNode(Data[Idx]));
                Idx++;
                Set_TVFunc(node, '1');
            }
            if (key > lev)
            {
                wk = node.TopNode;
                while(wk.NextNode!=null) wk = wk.NextNode;
                Set_TVFunc(wk, key);
            }
            if (key == lev) Set_TVFunc(node, lev);
        }
    
  4. TreeNode をパラメータにする Set_TVFunc() 関数は前回と同じです。

【NOTE】

  1. Root を親として Tree を展開するソースを元に、Root を無くして直接 TreeView から展開する方法を考えます。
    treeView1 でも node でも同じようにデータを登録することが出来ます。
        treeView1.Nodes.Add(new TreeNode(Data[Idx]));
        node.Nodes.Add(new TreeNode(Data[Idx]));
    
    従って TreeView を TreeNode でキャスト出来たら簡単なのですが、許されないようです。
        Set_TVFunc((TreeNode)treeView1, '1');
    
  2. NodeRoot に代わる TopNode を TreeView から取得出来たら良いのですが、取得した TreeNode は null になっています。
        TreeNode NodeRoot;
        NodeRoot = treeView1.TopNode;
    
  3. NodeRoot に登録されている node を取り出して TreeView に登録してみます。
        TreeNode NodeRoot, wk;
        wk = NodeRoot.FirstNode;
        treeView1.Nodes.Add(wk);
        wk = NodeRoot.LastNode;
        treeView1.Nodes.Add(wk);
    


【原因不明】

FirstNode と LastNode は表示出来るのですが、NextNode が null になり中央の node を表示することが出来ません。
NodeRoot の登録数を確認すると正常に登録されているのですが?
    wk = NodeRoot.FirstNode;
    wk = wk.NextNode;
実行環境は Windows10 & VS-2005 ですが、使い方が間違っているのでしょうか?
全ソースコードを掲載するので、ぜひアドバイスをお願いします。
using System;
using System.Drawing;
using System.Windows.Forms;

public class MyForm : Form
{
    private TreeView treeView1;
    string[]    Data=
    {   "1 鈴木", "1 田中", "1 佐藤", "0 " };
    int         Idx;

    public MyForm()
    {
        InitializeComponent();
        Load += new System.EventHandler(MyForm_Load);
    }

    private void InitializeComponent()
    {
        this.treeView1 = new System.Windows.Forms.TreeView();
        this.SuspendLayout();
        this.treeView1.Location = new System.Drawing.Point(12, 12);
        this.treeView1.Name = "treeView1";
        this.treeView1.Size = new System.Drawing.Size(250, 320);
        this.treeView1.TabIndex = 0;
        this.ClientSize = new System.Drawing.Size(280, 340);
        this.Controls.Add(this.treeView1);
        this.Name = "MyForm";
        this.ResumeLayout(false);
    }

    private void MyForm_Load(object sender, System.EventArgs e)
    {
        TreeNode NodeRoot, wk;
        treeView1.Nodes.Clear();
        NodeRoot = new TreeNode("1 Root");
        Idx = 0;
        Set_TVFunc(NodeRoot, '1');
        int cnt = NodeRoot.GetNodeCount(false);
        Console.WriteLine("Count= {0}", cnt);   //3件のデータが登録されている
        //treeView1.Nodes.Add(NodeRoot);        //3件のデータが正常に表示される
        
        wk = NodeRoot.FirstNode;
        treeView1.Nodes.Add(wk);                //1 鈴木 が表示される
        //wk = wk.NextNode;
        //treeView1.Nodes.Add(wk);              //wk が null になる
        wk = NodeRoot.LastNode;
        treeView1.Nodes.Add(wk);                //1 佐藤 が表示される
        
        treeView1.TopNode.Expand();
    }

    // TreeView に登録する再帰関数
    private void Set_TVFunc(TreeNode node, char lev)
    {
        node.Nodes.Add(new TreeNode(Data[0]));
        node.Nodes.Add(new TreeNode(Data[1]));
        node.Nodes.Add(new TreeNode(Data[2]));
    }
}

class form01
{   public static void Main()
    {   MyForm mf = new MyForm();
        Application.Run(mf);
    }
}

[Previous Chapter ↑] 階層 Data を TreeView に登録

超初心者のプログラム入門(C# Frame Work)