将MibBrowser这个程序的源代码看了无数遍后,发现在子节点的插入上是通过几个函数调用完成的。首先是读入一行文字,如果是包括关键字的话(如OBJECT
IDENTIFIER、OBJECT-TYPE),则取出其中的父节点、子节点、位置,通过一个函数调用,将根节点、父节点、子节点、位置这四项参数传递给一个插入节点的函数,该函数在接到这些参数后,再进行子节点的插入操作。但是在进行插入操作前,它先进行一个判断,传递过来的父节点是否在原来的树结构中存在,如果存在的话,则返回该节点的句柄(这一点很重要,因为我们要进行子节点的插入的话,父节点的句柄是必须要知道的),这一步操作又是通过一个函数来实现的,这个函数执行完以后,我们就把传递过来的父节点由一个字符类参数转换为一个父节点的句柄,从而打通了节点的操作。
但是这个函数隐藏在函数调用的函数调用中,如此重要却又不易弄懂,使得对于MIB浏览器的开发每每陷于困局,但是随着对于树状控件的学习的不断深入,终于可以自己编制一个小程序,在这个小程序中实现对这个函数的调用,从而便于对这个函数的学习和掌握,下面是这个小程序的实现步骤:
一、同样的是做一个基于单文档的MFC程序,基类为CFormView,画一个树状控件,导入一批图标。在初始化函数中实现树状控件的显示,源代码如下:
void CMytreebl0613View::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
//节点的图标
int n=0;
int i_count=5;
//载入图标
HICON icon[8];
icon[0]=AfxGetApp()->LoadIcon(IDI_ROOT1);
icon[1]=AfxGetApp()->LoadIcon(IDI_CLOSE_BOX);
icon[2]=AfxGetApp()->LoadIcon(IDI_OPEN_BOX);
//创建图像列表控件
CImageList *m_iImageList=new CImageList;
m_iImageList->Create(16,16,0,7,7);
m_iImageList->SetBkColor(RGB(255,255,255));
//这点很重要
//这样设置后可以避免某些图标显示的背景是黑的一块
for(n=0;n
{
m_iImageList->Add(icon[n]);
//把图标载入图像列表控件
}
m_tree.SetImageList(m_iImageList,TVSIL_NORMAL);
//为m_tree设置一个图像列表,使CtreeCtrl的节点显示不同的图标
//下面进行父根点的插入,以电脑外设为例
hRoot=m_tree.InsertItem("电脑外设",0,0,NULL);
//下面进行第一个子节点(显示器)的插入
hson=m_tree.InsertItem("显示器",1,1,hRoot);
//下面进行第一、二、三个孙子节点(液晶、纯平、球面)显示器的插入
hsonson=m_tree.InsertItem("液晶显示器",1,1,hson);
hsonson=m_tree.InsertItem("纯平显示器",1,1,hson);
hsonson=m_tree.InsertItem("球面显示器",1,1,hson);
//hcurrent=m_tree.GetChildItem(hRoot);
//下面进行第二个子节点(接口)的插入
hson=m_tree.InsertItem("接口",1,1,hRoot);
//下面进行第二的一、二孙子节点的插入
hsonson=m_tree.InsertItem("USB接口",1,1,hson);
hsonson=m_tree.InsertItem("串口",1,1,hson);
//下面要设计一个按钮实现树的遍历
}
程序运行界面如图1所示:

图1
其中左边部分就是我们所定义的一个树状控件,它有三级结构。右边部分是一个编辑框,作用是输出遍历树的结果,中间上部有一个按钮,点击该按钮就可调用FindNode函数,那么重要的是我们要将哪两个参数传递给,我反复看了例子中的源程序,发现应该是将根节点和本次读出的父节点作为参数传递,归结到我们现在这个小例子就是根节点为“电脑外设”,父节点为“显示器”。函数调用的代码如下:
void CMytreebl0613View::OnButton1()
{
// TODO: Add your control notification handler
code here
hcurrent=m_tree.GetChildItem(hRoot);
CString temp1;
//temp1取第一个子节点的名字
temp1=m_tree.GetItemText(hcurrent);
m_input1.ReplaceSel(temp1);
FindNode(hRoot,temp1);
}
FindNode函数的代码如下:
HTREEITEM CMytreebl0613View::FindNode(HTREEITEM hSubRoot,const
CString &text)
{
CString temp2;
//用temp2来获取节点的名称
if(hSubRoot==NULL)
{
AfxMessageBox("已经搜索到树的尾部!");
return NULL;
}
//判断是否符合条件,如是,返回该节点的句柄
if(m_tree.GetItemText(hSubRoot)==text)
return hSubRoot;
//移动到当前节点的下一个子节点
hSubRoot=m_tree.GetChildItem(hSubRoot);
temp2=m_tree.GetItemText(hSubRoot);
m_input1.ReplaceSel(temp2);
/* do {
HTREEITEM ht;
//递归调用FindNode函数
if((ht=FindNode(hSubRoot,text))!=NULL)
{
return
ht;
AfxMessageBox("递归调用起作用了!");
}
}
while((hSubRoot=m_tree.GetNextSiblingItem(hSubRoot))!=NULL);
return NULL;
*/
do
{
HTREEITEM ht;
//递归调用FindNode;
if
((ht=FindNode(hSubRoot,text)) !=NULL)
{
AfxMessageBox("递归调用起作用了!");
return ht;
}
} while
((hSubRoot=m_tree.GetNextSiblingItem(hSubRoot)) !=NULL);
return
NULL;
}
程序运行的界面如图2所示:

图2