在Windows应用程序开发中,MFC树形控件(CTreeCtrl)是一个常用的界面元素,它允许用户以树状结构浏览文件和文件夹。类似于Windows资源管理器左侧的文件浏览视图,但MFC树形控件提供了更多的灵活性,比如允许用户选择多个文件和文件夹进行进一步处理。用户可以通过每个文件和文件夹左侧的复选框来选择它们。当选择一个文件夹时,可以指定是否包括子文件夹中的文件。任何时候,都可以请求控件提供已选择的文件和文件夹列表,也可以获取有关任何文件夹中选择的文件数量的信息。
MFC树形控件支持以下复选框状态:
可以通过鼠标点击项目来切换复选框的状态。
首先,在对话框或表单视图中添加标准的树形控件,并确保启用了复选框样式。在树形控件属性的“更多样式”标签中进行设置。
然后,将一个新的位图资源添加到项目中,并将其命名为IDB_STATE。这个资源的BMP文件包含16个不同状态的复选框图像,其中5个是空的。
接下来,如果不想在控件中包含所有文件,而只想包含特定类型的文件,可以从CFileTreeCtrl派生一个新类。为此,需要在派生类中重写虚拟函数MatchExtension。
完成这些步骤后,需要使用类向导为对话框类添加一个树形控件资源的成员变量。然后转到对话框的头文件,并将AFX_DATA部分中的变量类型从CTreeCtrl更改为CFileTreeCtrl派生类的名称。
这里,将只描述CFileTreeCtrl的公共成员和虚拟函数MatchExtension。其他函数的功能可以通过源代码猜测。
BOOL DisplayTree()
调用这个函数来用文件填充文件树形控件。通常,这是在OnInitDialog()或OnInitialUpdate()中完成的。如果成功,函数返回true。
void AddHidFolder(int nFolder, CString strPath="")
在调用DisplayTree()之前调用这个函数,以告诉控件不显示某些文件夹。可以指定特殊文件夹的CSIDL标识符(使用nFolder),或者使用strPath指定文件夹的完整路径(在这种情况下,nFolder应该是0)。通常,不希望显示回收站和控制面板。因此,在调用DisplayTree()之前,可以添加以下代码:
m_FileTree.AddHidFolder(CSIDL_BITBUCKET);
m_FileTree.AddHidFolder(CSIDL_CONTROLS);
CString GetInfo(HTREEITEM hItem)
获取有关文件夹中选择的文件和文件夹数量的信息字符串。这是通过hItem,即树形控件项的句柄来指示的。字符串以以下格式返回:"Files: 15; Dirs: 22; SelFiles: 0; SelDirs: 0; PartDirs: 3",其中Files是文件夹中的总文件数,Dirs是子文件夹的总数,SelFiles是选定文件的数量,SelDirs是完全选定的子文件夹数量,PartDirs是部分选定的子文件夹数量。如果项是一个尚未展开的文件或文件夹,所有元素都是-1。例如,要获取当前选定文件夹的信息,可以使用:
m_strText = m_FileTree.GetInfo(m_FileTree.GetSelectedItem());
int GetSelectedFiles(CString* &SelFiles)
返回选定文件的数量。SelFiles参数指向包含所有选定文件完整名称的字符串数组。GetSelectedFiles内部分配了数组的内存,但需要自己使用delete[] SelFiles来删除它。
int GetSelectedFolders(CString* &SelFolders)
返回尚未展开的选定文件夹的数量。SelFolders参数指向包含选定文件夹完整名称的字符串数组,不包括关闭的"\"。返回的字符串的第一个字符指示选择的类型:"f"表示文件夹内只有文件,"F"表示只有子文件夹,"A"表示所有文件和所有子文件夹。GetSelectedFolders内部分配了数组的内存,但需要自己使用delete[] SelFolders来删除它。
CString GetSelectedFile()
返回包含文件树形控件中当前选定项的完整名称的字符串。
virtual bool MatchExtension(CString file)
如果想在CFileTreeCtrl派生类中只包含特定类型的文件,而不是所有文件,那么需要重写这个虚拟函数。函数获取文件的名称;如果应该包含该文件,则返回true,否则返回false。例如,如果想只显示EXE文件,可以这样做:
bool CMyFileTreeCtrl::MatchExtension(CString file)
{
CString strTemp = file.Right(4);
if (!strTemp.CollateNoCase(".EXE"))
return TRUE;
return FALSE;
}
如果根本不想显示文件,只想显示文件夹,可以这样重写函数:
bool CMyFileTreeCtrl::MatchExtension(CString file)
{
return FALSE;
}