CTreeView 迭代器






4.92/5 (22投票s)
2002年3月28日
4分钟阅读

161510

5459
一个迭代器,用于解析子树并在每个项目/节点上执行函数
引言
你是否发现自己编写了许多次相同的代码段来解析子树,因为你想对项目执行的操作不同。为了避免这样的代码,我编写了CTreeViewIterator
类。该类包含一个名为ApplyFunction
的方法,用于在子树的每个项目/节点上执行一个函数。
实现
我编写的类专用于类似 Explorer 的应用程序(那些左侧带有CTreeView
类的应用程序)。在这一部分,我们将看到如何在一般情况下使用CTreeViewIterator
。在 Adaptation 部分,我们将看到如何修改它以用于其他情况。
当您使用向导生成应用程序时,Visual C++ 不会给您选择CTreeView
类实现的选项。因此,您的应用程序中必须有一个CLeftView
。在LeftView.cpp文件中,在include
部分添加以下行。
#include "TreeViewIterator.h"
您现在可以在该模块中使用CTreeViewIterator
类了。
您必须定义一个函数,该函数将项目/节点作为参数接收。这个函数将是外部的,不属于您的CLeftView
类,即使它定义在同一个模块中。如果您不在该模块中定义它,请不要忘记创建一个定义,使其在该模块中可见。如果出于任何原因,您想将其设置为CLeftView
类的一个方法,请阅读 Adaptation 部分。该函数的签名是预定义的。它必须是这样的
int ExternalFunction ( CLeftView *tvTreeView, /* Handle on the tree view*/
HTREEITEM tiItem ) /* Item in the tree */
- 此函数必须返回一个整数,设置为
1
表示成功,否则为0
。 - 第一个参数是要传递的
CLeftView*
。它将接收一个指向CLeftView
的句柄,以便您使用。 - 第二个参数是要传递的
HTREEITEM
。它将接收一个指向当前正在解析的项目/节点的句柄。
例如,我们考虑这个函数
//*******************************************************************
//
// FUNCTION: ExternalDisplayItem
//
// RETURNS: int
//
// COMMENTS: External function to display the subtree as a list
//
//*******************************************************************
int ExternalDisplayItem (
CLeftView *tvTree, /* Handle on the tree */
HTREEITEM tiItem ) /* Item in the tree */
{
CTreeCtrl &tTree= tvTree->GetTreeCtrl ();
// store the name
tvTree->sFullList += tTree.GetItemText(tiItem) + "\r\n";
return ( 1);
}
这里的目标是将子树存储为string
中的一个列表。所以,外部函数需要做的就是获取名称并将其连接到完整的列表中。为此,它将使用CLeftView
中创建的一个名为sFullList
的属性(类型为CString
)。由于我们获得了指向CLeftView
的句柄作为第一个参数,只要该属性是public
的(否则,我们就需要使用public
方法,如get
和set
),就没有问题。使用此方法,您可以根据需要更新树项目/节点或CLeftView
。
现在您有了要应用于每个项目/节点的函数,您必须调用它。为此,您需要首先实现迭代器,然后使用正确的参数调用ApplyFunction
方法。
ApplyFunction
的签名是
int CTreeViewIterator::ApplyFunction (
CLeftView *tvView, /* Handler on the tree view */
HTREEITEM tiStart, /* Item to start with */
FuncPtrView fptrFunction ) /* Function to launch */
- 此函数返回一个整数:
1
表示成功,解析子树时出现问题为-1
,调用外部函数时出现问题为0
。 - 第一个参数是
CLeftView
派生自CTreeView
的句柄。 - 第二个参数是作为解析子树的根的项目/节点的句柄。
fptrFunction
是指向您先前创建的外部函数的函数指针。
使用我们之前的外部函数,我们得到了这段代码
//*******************************************************************
//
// FUNCTION: OnSelchanged
//
// RETURNS: void
//
// COMMENTS: Current selected item has changed
//
//
//*******************************************************************
void CLeftView::OnSelchanged (
NMHDR *pNMHDR, /* handle on event values */
LRESULT *pResult ) /* handle on event return value */
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW *) pNMHDR;
CTreeCtrl &tTree = this->GetTreeCtrl ();
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// create the iterator
CTreeViewIterator *ptrTree = (CTreeViewIterator *) &tTree;
// call the function
sFullList= "";
ptrTree->ApplyFunction (this, pNMTreeView->itemNew.hItem,
&ExternalDisplayItem );
GetDocument()->UpdateAllViews ( this, 1L, (CObject *) &sFullList );
*pResult = 0;
}
OnSelChanged
方法在用户在treeview
中选择了一个新项目/节点时触发。在这里,我们捕获了它以添加我们的函数调用。正如您所见,我们首先使用以下代码添加了迭代器的实现
CTreeViewIterator *ptrTree = (CTreeViewIterator *) tTree;
事实上,我们可以将CTreeCtrl
上的迭代器视为一个带有特殊方法的 shell。因此,在ApplyFunction
方法内部,我们将解析CTreeCtrl
的内容。
我们现在需要获取参数
- 第一个参数,即
CLeftView
的句柄很容易获得,它就是这个变量。 - 第二个参数是项目/节点的句柄。由于我们在捕获新选择的方法中,我们将使用两行从参数
pNMHDR
中提取项目地址NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW *) pNMHDR; // to cast the event param pNMTreeView->itemNew.hItem // to refer to the new selected item
- 最后一个参数是我们创建的外部函数的句柄。
这样,我们就得到了以下调用
ptrTree->ApplyFunction (this, pNMTreeView->itemNew.hItem, &ExternalDisplayItem );
由于此事件可能会被捕获多次,因此我们在解析子树之前初始化变量sFullList
。
当ApplyFunction
完成后,我们使用UpdateAllViews
方法使用生成的string
更新其他视图。
这样,我们就完成了。捕获UpdateAllViews
事件不是这里的主题,但您可以查看示例项目以获得一些想法。
适应性
本节将向您解释如何升级CTreeViewIterator
以适应您自己的情况。我将其写成一个 FAQ。我会根据您提出的案例进行更新。那么,您的问题是什么?
问题:我的CTreeView
类没有命名为CLeftView
。
回答:在以下位置更改CTreeView
类名
- 函数指针的签名
ApplyFunction
的定义ApplyFunction
的实现
问题:我想将调用的函数设置为我的CLeftView
类的一个方法。
回答:您只需更改函数指针的签名以添加您的类。例如,可以尝试这样做
- 将外部函数更改为
CLeftView
类中的一个名为DisplayItem
的public
方法。 - 将签名更改为
typedef int ( CLeftView::*FuncPtrView ) ( CLeftView * tTree, HTREEITEM tiItem );
- 将
ApplyFunction
方法的调用更改为ptrTree->ApplyFunction (this, pNMTreeView->itemNew.hItem, &CLeftView::DisplayItem );
- 在
ApplyFunction
实现中,将函数调用更改为( tvView->*fptrFunction ) ( tvView, tiCurrItem )
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。