表名
Leaf
字段
id 类型为int 表示树中的节点的id值
pareid 类型为int 表示树中的节点的父级节的id值
name 类型string 表示节点的标签
树形节点的id值将通过以下方法取得,根节点的父级节点的id值均会被设置成“-1”。
/// <summary>
/// 获取ID号
/// </summary>
/// <returns>ID号</returns>
private int GetNum()
{
int x=0;
bool t=false;
Yds.YdsTree.PublicTree.numList.Sort();//将id进行排序(从小到大)
if(Yds.YdsTree.PublicTree.numList.Count ==0) return 0;//如果此集合为空,则返回id =0
do
{
foreach(int a in Yds.YdsTree.PublicTree.numList) //遍历此集合
{
if(x!=a) //如果id此处不连续,则中断跳出、
{
t=true;
break;
}
x=x+1;
}
if(t) break;
}
while(x<int.MaxValue);
return x;//返回找到的id值
}
以下仅为从数据库中读取数据来生成树的主要代码
namespace Yds
{
namespace YdsTree
{
public class PublicTree
{
public PublicTree()
{
}
public static ArrayList numList = new ArrayList();//所有节点键值集合
public static OleDbConnection Conn;//数据库连接
}
/// <summary>
/// 定制自定义树形节点
/// </summary>
public class LeafNode:TreeNode
{
public readonly int Id;//键值
public int PareId;//父级健值
public LeafNode(int id ,int pareid,string name)
{
this.Id =id;
this.PareId =pareid;
this.Text =name;
}
public override string ToString()
{
return this.Text ;
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
public override bool Equals(object obj)
{
LeafNode temobj=obj as Yds.YdsTree.LeafNode ;
if(temobj==null) return false;
if(temobj.Id ==this.Id )
return true;
return false;
}
}
/// <summary>
/// 自定义树,实现添加指定类型的节点和一些指定的动作与数据库关联一起
/// </summary>.
public class TreeP:TreeView
{
private Yds.YdsTree.LeafNode Xtemnode;
public TreeP()
{
}
/// <summary>
/// 对数据连接赋值的同时从数据库中读取节点,初始化树
/// </summary>
public OleDbConnection ChangeDataConn
{
get
{
return Yds.YdsTree.PublicTree.Conn ;
}
set
{
if(value==null) return;
try
{
Yds.YdsTree.PublicTree.Conn =value;
Yds.YdsTree.PublicTree.Conn.Open();
}
catch
{
System.Windows.Forms.MessageBox.Show("数据连接未成功!");
return;
}
//树形节点初始化(清空);
this.Nodes.Clear();
Yds.YdsTree.PublicTree.numList.Clear();
try
{
string sql = "SELECT * FROM Leaf ";
OleDbCommand cmd=new OleDbCommand(sql,Yds.YdsTree.PublicTree.Conn);
OleDbDataReader rd=cmd.ExecuteReader();
Yds.YdsTree.LeafNode temleaf;
while(rd.Read())
{
temleaf=new LeafNode(System.Convert.ToInt32(rd["id"].ToString()),System.Convert.ToInt32(rd["pareid"].ToString()),rd["name"].ToString());
this.addNode(temleaf);//将此节点添加至树中。
}
this.sortRoot();
rd.Close();
}
catch(System.Data.OleDb.OleDbException ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
Yds.YdsTree.PublicTree.Conn.Close();
}
}
private void addNode(Yds.YdsTree.LeafNode temnode)
{
this.Xtemnode =new LeafNode(-1,-1,false,"");//初始化Xtemnode
this.FindNode(temnode.PareId ,this.Nodes);//查找它的父级节点,结果将保存在Xtemnode
Yds.YdsTree.PublicTree.numList.Add(temnode.Id);//收集键值
if(this.Xtemnode.Id ==-1)
this.Nodes.Add(temnode);//如果没找到则将其作为根添加至树中。
else
this.Xtemnode.Nodes.Add(temnode);
}
/// <summary>
/// 重新对根进行整理,直到所有的根节点均找到它的上级节点
/// </summary>
private void sortRoot()
{
foreach(Yds.YdsTree.LeafNode temnode in this.Nodes)
{
foreach(Yds.YdsTree.LeafNode temnodex in this.Nodes )
{
if(temnode.PareId ==temnodex.Id )
{
this.Nodes.Remove(temnode);
temnodex.Nodes .Add(temnode);
sortRoot();
}
}
}
}
private void FindNode(int id,System.Windows.Forms.TreeNodeCollection temnodes)
{
foreach(Yds.YdsTree.LeafNode node in temnodes)
{
if(id ==node.Id )
{
this.Xtemnode = node;
break;
}
else
this.FindNode(id,node.Nodes);
}
}
}
}
}
主要问题是如果一个子节点先从数据库中读取添加至树中,而其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,有哪位师付能帮我改正下?代码要简短,效率越高越好!谢谢!!
17 个解决方案
#1
学院派:递归
企业派:xml
企业派:xml
#2
国内著名ERP派:
ccode
001
001001
001001001
002
002001
002001001
这种方法你会体会到未来各类查询时的方便性,妙不可言...................
保存父ID的做法,真属于垃圾做法,虽然这的许多专家乐此不彼
当然,如果楼主需要一个无限级次的树,那不要用这种方法
不怕拍砖,没人骂我剽窃就行了
ccode
001
001001
001001001
002
002001
002001001
这种方法你会体会到未来各类查询时的方便性,妙不可言...................
保存父ID的做法,真属于垃圾做法,虽然这的许多专家乐此不彼
当然,如果楼主需要一个无限级次的树,那不要用这种方法
不怕拍砖,没人骂我剽窃就行了
#3
脑袋大中。。。
#4
to jointan:
前一种方法好是好,就是对于每级都要定义节点的id格式,每级数量有限制,以前用VB做过。
现在我就是要做个无限级次的树。方法是
依次从数据库中读取数据,每读取一个数据生成一个节点,在已有的树中查找它的父级,如果找到则添加至它的下级中,如果没找到则暂时作为根添加至树中。当从数据库读取数据完毕则已建立了一个初步符合要术的树,但是此时如果有的节点其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,能帮我改正下?代码要简短,效率越高越好!谢谢!!
我正在使用《Csdn收音机》第一时间获取最新动态!
前一种方法好是好,就是对于每级都要定义节点的id格式,每级数量有限制,以前用VB做过。
现在我就是要做个无限级次的树。方法是
依次从数据库中读取数据,每读取一个数据生成一个节点,在已有的树中查找它的父级,如果找到则添加至它的下级中,如果没找到则暂时作为根添加至树中。当从数据库读取数据完毕则已建立了一个初步符合要术的树,但是此时如果有的节点其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,能帮我改正下?代码要简短,效率越高越好!谢谢!!
我正在使用《Csdn收音机》第一时间获取最新动态!
#5
在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到
#6
在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到
这样不行,因为每个新节点id是通过GetNum()方法获取(见前面贴过的代码),而树中的节点在实际操作过程中是不断添加或删除节点的。这样就造成有的节点的id值可能比它的父级节点的id值还大,
我正在使用《Csdn收音机》第一时间获取最新动态!
这样不行,因为每个新节点id是通过GetNum()方法获取(见前面贴过的代码),而树中的节点在实际操作过程中是不断添加或删除节点的。这样就造成有的节点的id值可能比它的父级节点的id值还大,
我正在使用《Csdn收音机》第一时间获取最新动态!
#7
#8
建议你改一下(添加两个方法,一个字段)
以上代码我没数库,所以没测试
private string GetParentID(int id)
{
//查找只定ID的父ID,查不到返回-1;
}
private string GetParentName(int Name)
{
//查找只定ID的父ID名称,查不到返回"";
}
private ArrayList m_NodeList = new ArrayList();//保存已添加结点集合
private void AddNode(Yds.YdsTree.LeafNode newNode)
{
foreach (LeafNode node in m_NodeList)
{
if (node.Id == newNode.Id)//节点已被添加
return;
}
if(newNode.PareId == -1)//根节点
{
this.m_NodeList.Add(newNode);
this.Nodes.Add(newNode);
return;
}
foreach (LeafNode node in m_NodeList)
{
if (node.Id == newNode.PareId)
{
this.m_NodeList.Add(newNode);
node.Nodes.Add(newNode);
return;
}
}
LeafNode parentNode = new LeafNode(parentNode.PareId, GetParentID(newNode.PareId), GetParentName(newNode.PareId));
AddNode(parentNode);//递归调用,逐级创建父节点
this.m_NodeList.Add(newNode);
parentNode.Nodes.Add(newNode);
}
}
以上代码我没数库,所以没测试
#9
+1
#10
还有一种方式。对数据结构中的树进行改造,放到数据库里面。有个老外是这么做的。
#11
现已改好了,大家看看可行,还没调试。
jointan的方法也不错,我以后考虑改写的。
由于本人不是从事这个行业的,白天要上班,只要晚上抽空看一下CSDN,回贴时间不及时,请大家见谅!!
我正在使用《Csdn收音机》第一时间获取最新动态!
jointan的方法也不错,我以后考虑改写的。
由于本人不是从事这个行业的,白天要上班,只要晚上抽空看一下CSDN,回贴时间不及时,请大家见谅!!
private ArrayList m_NodeList = new ArrayList();//存储未找到父的节点集合
private void addNode(Yds.YdsTree.LeafNode temnode)
{
if (temnode.PareId == -1)
{
this.Nodes.Add(temnode);
return;
}
this.Xtemnode = new LeafNode(-1, -1, "");
this.FindNode(temnode.PareId, this.Nodes););//从已组成的树形视图中查找父节点
Yds.YdsTree.PublicTree.numList.Add(temnode.Id);
if (this.Xtemnode.Id == -1)
m_NodeList.Add(nodeX);//如果没找到则将此节点存放在m_NodeList集合中。
else
this.Xtemnode.Nodes.Add(temnode);//如果找到了,则将此节点加入到视图树中。
}
//以下是将m_NodeList中的节点在视图树中找到它的父级节点并添加上
private void sortRoot(ArrayList nodeX)
{
if (nodeX.Count == 0) return;
foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
{
this.Xtemnode=new LeafNode(-1,-1,"");
FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中,从m_NodeList移除此节点
m_NodeList.Remove(temnode);
}
sortRoot(nodeX);
}
//以下是改写的
public OleDbConnection ChangeDataConn
{
...
this.m_NodeList.Clear();
while(rd.Read())
{
... this.addNode(temleaf,m_NodeList);
}
this.sortRoot(m_NodeList);
rd.Close();
}
...
}
我正在使用《Csdn收音机》第一时间获取最新动态!
#13
楼上都很好
#14
比较喜欢xml
#15
8楼正解,如果树不是很大的话,我觉得楼主可以用递归,
#16
#17
大家没有发现我下面的有个错误吗?
现已改写成
我正在使用《Csdn收音机》第一时间获取最新动态!
private void sortRoot(ArrayList nodeX)
{
if (nodeX.Count == 0) return;
foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
{
...
m_NodeList.Remove(temnode);//在集合的遍历过程中不可移除对象
}
sortRoot(nodeX);
}
现已改写成
private void sortRoot(ArrayList nodeX)
{
if (nodeX.Count == 0) return;
ArrayList temx = new ArrayList();
foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
{
this.Xtemnode=new LeafNode(-1,-1,"");
FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中
temx.Add(temnode);
}
foreach (Yds.YdsTree.LeafNode x in temx)
{
m_NodeList.Remove(x);
}
sortRoot(nodeX);
}
我正在使用《Csdn收音机》第一时间获取最新动态!
#1
学院派:递归
企业派:xml
企业派:xml
#2
国内著名ERP派:
ccode
001
001001
001001001
002
002001
002001001
这种方法你会体会到未来各类查询时的方便性,妙不可言...................
保存父ID的做法,真属于垃圾做法,虽然这的许多专家乐此不彼
当然,如果楼主需要一个无限级次的树,那不要用这种方法
不怕拍砖,没人骂我剽窃就行了
ccode
001
001001
001001001
002
002001
002001001
这种方法你会体会到未来各类查询时的方便性,妙不可言...................
保存父ID的做法,真属于垃圾做法,虽然这的许多专家乐此不彼
当然,如果楼主需要一个无限级次的树,那不要用这种方法
不怕拍砖,没人骂我剽窃就行了
#3
脑袋大中。。。
#4
to jointan:
前一种方法好是好,就是对于每级都要定义节点的id格式,每级数量有限制,以前用VB做过。
现在我就是要做个无限级次的树。方法是
依次从数据库中读取数据,每读取一个数据生成一个节点,在已有的树中查找它的父级,如果找到则添加至它的下级中,如果没找到则暂时作为根添加至树中。当从数据库读取数据完毕则已建立了一个初步符合要术的树,但是此时如果有的节点其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,能帮我改正下?代码要简短,效率越高越好!谢谢!!
我正在使用《Csdn收音机》第一时间获取最新动态!
前一种方法好是好,就是对于每级都要定义节点的id格式,每级数量有限制,以前用VB做过。
现在我就是要做个无限级次的树。方法是
依次从数据库中读取数据,每读取一个数据生成一个节点,在已有的树中查找它的父级,如果找到则添加至它的下级中,如果没找到则暂时作为根添加至树中。当从数据库读取数据完毕则已建立了一个初步符合要术的树,但是此时如果有的节点其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,能帮我改正下?代码要简短,效率越高越好!谢谢!!
我正在使用《Csdn收音机》第一时间获取最新动态!
#5
在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到
#6
在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到
这样不行,因为每个新节点id是通过GetNum()方法获取(见前面贴过的代码),而树中的节点在实际操作过程中是不断添加或删除节点的。这样就造成有的节点的id值可能比它的父级节点的id值还大,
我正在使用《Csdn收音机》第一时间获取最新动态!
这样不行,因为每个新节点id是通过GetNum()方法获取(见前面贴过的代码),而树中的节点在实际操作过程中是不断添加或删除节点的。这样就造成有的节点的id值可能比它的父级节点的id值还大,
我正在使用《Csdn收音机》第一时间获取最新动态!
#7
#8
建议你改一下(添加两个方法,一个字段)
以上代码我没数库,所以没测试
private string GetParentID(int id)
{
//查找只定ID的父ID,查不到返回-1;
}
private string GetParentName(int Name)
{
//查找只定ID的父ID名称,查不到返回"";
}
private ArrayList m_NodeList = new ArrayList();//保存已添加结点集合
private void AddNode(Yds.YdsTree.LeafNode newNode)
{
foreach (LeafNode node in m_NodeList)
{
if (node.Id == newNode.Id)//节点已被添加
return;
}
if(newNode.PareId == -1)//根节点
{
this.m_NodeList.Add(newNode);
this.Nodes.Add(newNode);
return;
}
foreach (LeafNode node in m_NodeList)
{
if (node.Id == newNode.PareId)
{
this.m_NodeList.Add(newNode);
node.Nodes.Add(newNode);
return;
}
}
LeafNode parentNode = new LeafNode(parentNode.PareId, GetParentID(newNode.PareId), GetParentName(newNode.PareId));
AddNode(parentNode);//递归调用,逐级创建父节点
this.m_NodeList.Add(newNode);
parentNode.Nodes.Add(newNode);
}
}
以上代码我没数库,所以没测试
#9
+1
#10
还有一种方式。对数据结构中的树进行改造,放到数据库里面。有个老外是这么做的。
#11
现已改好了,大家看看可行,还没调试。
jointan的方法也不错,我以后考虑改写的。
由于本人不是从事这个行业的,白天要上班,只要晚上抽空看一下CSDN,回贴时间不及时,请大家见谅!!
我正在使用《Csdn收音机》第一时间获取最新动态!
jointan的方法也不错,我以后考虑改写的。
由于本人不是从事这个行业的,白天要上班,只要晚上抽空看一下CSDN,回贴时间不及时,请大家见谅!!
private ArrayList m_NodeList = new ArrayList();//存储未找到父的节点集合
private void addNode(Yds.YdsTree.LeafNode temnode)
{
if (temnode.PareId == -1)
{
this.Nodes.Add(temnode);
return;
}
this.Xtemnode = new LeafNode(-1, -1, "");
this.FindNode(temnode.PareId, this.Nodes););//从已组成的树形视图中查找父节点
Yds.YdsTree.PublicTree.numList.Add(temnode.Id);
if (this.Xtemnode.Id == -1)
m_NodeList.Add(nodeX);//如果没找到则将此节点存放在m_NodeList集合中。
else
this.Xtemnode.Nodes.Add(temnode);//如果找到了,则将此节点加入到视图树中。
}
//以下是将m_NodeList中的节点在视图树中找到它的父级节点并添加上
private void sortRoot(ArrayList nodeX)
{
if (nodeX.Count == 0) return;
foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
{
this.Xtemnode=new LeafNode(-1,-1,"");
FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中,从m_NodeList移除此节点
m_NodeList.Remove(temnode);
}
sortRoot(nodeX);
}
//以下是改写的
public OleDbConnection ChangeDataConn
{
...
this.m_NodeList.Clear();
while(rd.Read())
{
... this.addNode(temleaf,m_NodeList);
}
this.sortRoot(m_NodeList);
rd.Close();
}
...
}
我正在使用《Csdn收音机》第一时间获取最新动态!
#12
#13
楼上都很好
#14
比较喜欢xml
#15
8楼正解,如果树不是很大的话,我觉得楼主可以用递归,
#16
#17
大家没有发现我下面的有个错误吗?
现已改写成
我正在使用《Csdn收音机》第一时间获取最新动态!
private void sortRoot(ArrayList nodeX)
{
if (nodeX.Count == 0) return;
foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
{
...
m_NodeList.Remove(temnode);//在集合的遍历过程中不可移除对象
}
sortRoot(nodeX);
}
现已改写成
private void sortRoot(ArrayList nodeX)
{
if (nodeX.Count == 0) return;
ArrayList temx = new ArrayList();
foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
{
this.Xtemnode=new LeafNode(-1,-1,"");
FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中
temx.Add(temnode);
}
foreach (Yds.YdsTree.LeafNode x in temx)
{
m_NodeList.Remove(x);
}
sortRoot(nodeX);
}
我正在使用《Csdn收音机》第一时间获取最新动态!