主题:  再叙无限级分类法

蓝鲸

职务:版主
等级:5
金币:42.1
发贴:2614
#12004/11/14 1:08:29
以前写了编关于无限级分类的文章,但主要是用于Windows编程上用的,因为与treeView控件相结合。参考:
blog.csdn.net/dhlhh/archive/2004/10/13/134438.aspx
修正程序:
blog.csdn.net/dhlhh/archive/2004/10/15/138105.aspx

这次因要用到ASP.net上编程,所以以上方法有些不同了。原打算用数据结构写一个类,但觉太烦,递归编程不一定效率很高,所以从另一个角度编程,比较适合网络程序,不过也能用在WINDOWS上,只是样子不太好看。WEB中主要用于后台管理。

类的调试是在WINDOWS FORM上,如下样式

图片如下:

编辑历史:[此帖最近一次被 蓝鲸 编辑过(编辑时间:2004-11-14 20:09:08)]

非常大鱼

蓝鲸

职务:版主
等级:5
金币:42.1
发贴:2614
#22004/11/14 1:16:22
数据库分类的建立已在上文中说了,请参考以上两个链接
数据表字段:SortID、SortName、ParentID、Index(同一子族里的排位)、IsEnd

方法先建立一个Node节点的类,比较简单,我也不想详细说了

    public class Node
    {
        private string mName;        // 节点名
        private int mID;        // Id号
        private int mParentID;        // 父节点ID号
        private int mIndex;        // 每个子节点下的序号
        private int mIndent;        // 缩进
        private string mNamePath;    // 名字路径
        private string mIDPath;        // Id路径
        private object mContent;    // 内容

        public string Name
        {
            get
            {
                return mName;
            }
            set
            {
                mName = value;
            }
        }

        public int ID
        {
            get
            {
                return mID;
            }
            set
            {
                mID = value;
            }
        }

        // .......太多了,不往下写了

        public Node()
        {
            mName = "";
            mID = 0;
            mParentID = 0;
            mIndex = 0;
            mIndent = 0;
            mNamePath = "";
            mIDPath = "";
        }
    }


非常大鱼

蓝鲸

职务:版主
等级:5
金币:42.1
发贴:2614
#32004/11/14 1:22:48
下面的TreeList类是关键的类,它的方法主要是用一数组存放Node,并在添加中判断插入数组的位置、缩进,并动态添加路径。路径很重要,特别是IDPath,可用于以后的搜索、插入等。

IDPath的增加方法,是在找到父节点后,路径为父类的路径+自身ID

    public class TreeList
    {
        private ArrayList mNodes;    // Node集合

        public ArrayList Nodes
        {
            get
            {
                return mNodes;
            }
        }

        public TreeList()
        {

        }

        /// <summary>
        /// 添加一个节点
        /// </summary>
        public bool AddNode(Node node)
        {
            // 空节点不添加
            if (node == null)
            {
                return false;
            }

            if (mNodes.Count == 0)
            {
                // 添加根节点
                if (node.ID == 0)
                {
                    node.ParentID = 0;    
                    node.Name = "";
                    node.NamePath = "root";
                    node.IDPath = "0";
                    node.Index = 1;
                    node.Indent = -1;

                    mNodes.Add((object)node);

                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                bool nodeFound = false;
                Node pNode;
                int iPosition = 0;        // 插入点位置

                for (int ndIndex = (mNodes.Count - 1); ndIndex >= 0; ndIndex--)
                {
                    pNode = (Node)mNodes[ndIndex];

                    // 如果找到Node的ID与添加Node的父类ID号相同
                    if ( pNode.ID == node.ParentID )
                    {
                        nodeFound = true;

                        node.NamePath = pNode.NamePath + "\\" + node.Name;
                        node.IDPath = pNode.IDPath + "\\" + node.ID.ToString();
                        node.Indent = pNode.Indent + 1;

                        iPosition = ndIndex + 1;

                        // 查找序号比它大的节点
                        for ( int i = iPosition; i < mNodes.Count; i++ )
                        {
                            if ( ((Node)mNodes[i]).IDPath.IndexOf(pNode.IDPath) != 0 )
                            {
                                break;
                            }
                            else
                            {
                                if ( ((Node)mNodes[i]).ParentID == node.ParentID)                                    
                                {
                                    if ( ((Node)mNodes[i]).Index > node.Index )
                                    {
                                        iPosition = i;
                                        break;
                                    }
                                    else
                                    {
                                        iPosition = i+1;
                                    }
                                }
                                else
                                {
                                    iPosition = i + 1;
                                }
                            }
                        }

                        // 把节点插入到数组
                        mNodes.Insert(iPosition, (object)node);
                        return true;
                    }
                }

                if (!nodeFound) return false;
            }

            return false;
        }

        /// <summary>
        /// 重置树
        /// </summary>
        public void ResetTreeList(ArrayList srcNodes)
        {
            mNodes = new ArrayList();

            Node node = new Node();
            AddNode(node);

            while (srcNodes.Count > 0)
            {
                for (int i = 0; i < srcNodes.Count; i++)
                {
                    if (AddNode((Node)srcNodes[i]))
                    {
                        srcNodes.RemoveAt(i);
                        break;
                    }
                }
            }
        }
    }


非常大鱼

蓝鲸

职务:版主
等级:5
金币:42.1
发贴:2614
#42004/11/14 1:30:38
用法:

先把数据从数据库导入,存放于DataSet中,并把DateSet中每行的值生成一Node对象,并添加至临时数组中。

            if (dsTree.Tables["Sort"].Rows.Count > 0)
            {
                for (int i = 0; i < dsTree.Tables["Sort"].Rows.Count; i++)
                {
                    nd = new Node();
                    nd.Name = dsTree.Tables["Sort"].Rows[i]["SortName"].ToString();
                    nd.ID = (int)dsTree.Tables["Sort"].Rows[i]["SortID"];
                    nd.ParentID = (int)dsTree.Tables["Sort"].Rows[i]["ParentID"];
                    nd.Index = (int)dsTree.Tables["Sort"].Rows[i]["Index"];

                    arrNode.Add(nd);
                }
            }

            treeSort = new TreeList();
            treeSort.ResetTreeList(arrNode);


这样一个树就形成了。

我这里用listBox 和comboBox来显示树的方法,当然在ASP.NET的下拉菜单中方法是差不多的,我只是调试用的。
显示函数:

        private void resetView()
        {
            string strTemp;

            listBox1.Items.Clear();
            comboBox1.Items.Clear();
            

            foreach (Node nd in treeSort.Nodes)
            {
                strTemp = "";
                if (nd.ID != 0)
                {                    
                    if (nd.Indent == 1)
                    {
                        strTemp = " ├";
                    }
                    else if (nd.Indent > 1)
                    {
                        for (int i = 2; i <= nd.Indent + 1; i++)
                        {
                            strTemp += " ";
                        }
                        strTemp += "├";
                    }

                    strTemp += nd.Name;
                    listBox1.Items.Add(strTemp);
                    comboBox1.Items.Add(strTemp);
                }
            }
        }


点击listBox,可显示节点的路径
        private void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            textBox1.Text = ((Node)treeSort.Nodes[listBox1.SelectedIndex + 1]).NamePath;
            textBox2.Text = ((Node)treeSort.Nodes[listBox1.SelectedIndex + 1]).IDPath;
        }


非常大鱼

dreamexpress_5d

职务:普通成员
等级:1
金币:10.0
发贴:2229
#52004/11/17 15:25:19
好贴,学习一下!



蓝鲸

职务:版主
等级:5
金币:42.1
发贴:2614
#62004/11/17 15:56:18
声明一点,这类还没完,只是最基本的。
我自己已实现了一些图标等功能,想有空加工成可以展开子节点的,需要加属性。

方法是在Node类里加上FirstChildNode、LastChildNode、NextNode、PrevNode、Nodes集合及Expended、Visibled等属性后,即方便操作树了。

这里卖些关子了,一是代码很长,另自己成果也想留着,再加上代码还是不成熟,这里只是探讨性的。


非常大鱼