C# winform 关于treeView控件的实战

treeView 控件应该是所有控件里最难用代码操作的,因为需要时刻分析各项数据的先后关系,导致逻辑较为复杂难写,以下是利用百度AI的NLP服务里,依存句法分析的api返回的数据,来展示treeView控件的使用。最终效果如图:
在这里插入图片描述
参考链接:

  1. 百度AI:https://ai.baidu.com/ai-doc/NLP/ik6z52biz#%E4%BE%9D%E5%AD%98%E5%8F%A5%E6%B3%95%E5%88%86%E6%9E%90
  2. treeView使用:https://blog.csdn.net/ping_Kingzero/article/details/119493112

为了弄清代码含义,先展示百度的api的返回值含义和调用的代码,再来看treeView的代码:
在这里插入图片描述

using Newtonsoft.Json;
namespace nlp_app.Baidu
{
    public class DepParserApp
    {
        public List<DepParserItemsItem>? DepParserDemo(string text)
        {
            NLPApp appInfo = NLPApp.getAppInfo();
            // 调用依存句法分析,可能会抛出网络等异常,请使用try/catch捕获
            var jsonResult = appInfo.Client.DepParser(text);
            DepParserRoot result = JsonConvert.DeserializeObject<DepParserRoot>(jsonResult.ToString());
            if (result != null)
            {
                return result.items;
            }
            return null;
        }
    }
    public class DepParserItemsItem
    {
        public string id { get; set; }
        public string word { get; set; }
        public string postag { get; set; }
        public string head { get; set; }
        public string deprel { get; set; }
    }
    public class DepParserRoot
    {
        public ulong log_id { get; set; }
        public string text { get; set; }
        public List<DepParserItemsItem> items { get; set; }
    }
}

接下来是treeView怎么实现的代码。基本思路是:

  1. 先用双层循环,按照先父后子的结点之间引用顺序来排序进入SortedList;
  2. 然后用Map记录每个结点的id(作为Key),父结点的id(在此处是head)、在treeView里位于上一层节点的第几个子节点(索引index),后两项装进数组作为Value;
  3. 遍历SortedList,因为是父子关系有序的,故不用担心先遍历的点需要指向后遍历的点。此时对每个遍历的点按照父节点关系(head),通过查Map,依次装入一个栈里,然后再依次出栈,栈顶一定是根节点。用treeView的SelectedNode指向当前层次的结点,最后插入当前遍历的结点。记得还要记录当前结点在treeView里的索引,并放入Map里以供后面查询。
private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = checkTextLength(textBox1.Text); //输入的文本
            treeView1.Nodes.Clear(); // 首先清理之前使用过的treeView结果
            try
            {
                DepParserApp depParserApp = new DepParserApp();
                List<DepParserItemsItem>? depParserItemsItems = depParserApp.DepParserDemo(UTF8ToGBK(textBox1.Text));

                if (depParserItemsItems == null || depParserItemsItems.Count == 0)
                {
                    MessageBox.Show("发生错误:返回null值,可能由于status或retcode不为0,或网络查询返回了null");
                    return;
                }

                SortedList<int, DepParserItemsItem> treeView_sortedList = new SortedList<int, DepParserItemsItem>();
                string index; // 用于记录当前查找的元素,它的head属性值应该是多少
                int p = 0;
                int q = 0;
                // 为了使用treeView,首先对List<DepParserItemsItem> 里的元素,按照head属性的先后顺序,
                // 放到一个SortedList里,按照:根节点→一级节点→二级节点... 排列为层次顺序。使用双层循环完成排序
                while (depParserItemsItems.Count > 0)
                {
                    if (treeView_sortedList.Count == 0) { index = "0"; } // 初始时,需要找head为0的那个元素,其余时刻head是i值对应索引的SortedList元素的id值
                    else
                    {
                        index = treeView_sortedList[p - 1].id;
                    }
                    for (int j = 0; j < depParserItemsItems.Count; j++)
                    {
                        if (depParserItemsItems[j].head == index)
                        {
                            treeView_sortedList.Add(q, depParserItemsItems[j]);
                            q++;
                            depParserItemsItems.RemoveAt(j);
                            j--;
                        }
                    }
                    p++;
                }

                NLPApp appInfo = NLPApp.getAppInfo();
                // 定义一个Map,key是List<DepParserItemsItem> 里元素的id,value是一个3个元素的数组:[head, list_index, treeView_index]
                // head即当前元素id对应的父节点的id,list_index即当前元素在treeView_sortedList里的索引,treeView_index即当前节点在treeView里的序号
                Hashtable map = new Hashtable();
                for (int i = 0; i < treeView_sortedList.Count; i++)
                {
                    string temp = treeView_sortedList[i].word + "(" + appInfo.DEPRELTable[treeView_sortedList[i].deprel] + ")";
                    if (i == 0)
                    {
                        this.treeView1.Nodes.Add(new TreeNode(temp));
                        int[] vs = new int[3] { 0, 0, 0 };
                        map.Add(treeView_sortedList[i].id, vs);
                    }
                    else
                    {
                        this.treeView1.SelectedNode = this.treeView1.Nodes[0]; // 每次从根节点出发
                                                                               // 使用栈来完成获取当前节点位置
                        Stack stack = new Stack();
                        string locate = treeView_sortedList[i].head;
                        stack.Push(((int[])map[locate])[2]);
                        while (((int[])map[locate])[0] != 0)
                        {
                            locate = ((int[])map[locate])[0].ToString();
                            stack.Push(((int[])map[locate])[2]);
                        }
                        while (stack.Count > 0)
                        {
                            int j = (int)stack.Pop();
                            if (j == 0) { continue; }
                            this.treeView1.SelectedNode = this.treeView1.SelectedNode.Nodes[j];
                        }
                        int num = this.treeView1.SelectedNode.Nodes.Count;
                        this.treeView1.SelectedNode.Nodes.Add(new TreeNode(temp));

                        int[] vs = new int[3] { int.Parse(treeView_sortedList[i].head), i, num };
                        map.Add(treeView_sortedList[i].id, vs);
                    }
                }
                this.treeView1.ExpandAll();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值