CTreeCtrl是windows界面开发中经常用到,也是windows系统中经常见到的一种控件,比如文件夹目录,那就是一个典型的应用,不过,很多资料中,对于CTreeCtrl的数据的处理,存在一些问题。我们可以先看下面的代码:
void CFileTreeCtrl::InitTreeCtrl(const CString& strDir, HTREEITEM hItem)
{
CFileFind finder;
CString strFindDir = strDir;
strFindDir += _T("\\*.*");
BOOL bWorking = finder.FindFile(strFindDir);
while(bWorking)
{
HTREEITEM hItemTmp;
bWorking = finder.FindNextFile();
if(finder.IsDirectory() && !finder.IsDots())
{
CString szFileName = finder.GetFileName();
CString strNextDir = finder.GetFilePath();
SHFILEINFO sfi;
SHGetFileInfo(strNextDir+_T("\\"), 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX|SHGFI_DISPLAYNAME);
TV_INSERTSTRUCT TCItem;
ZeroMemory(&TCItem,sizeof(TV_INSERTSTRUCT));
TCItem.hInsertAfter = TVI_LAST;
TCItem.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_STATE|TVIF_SELECTEDIMAGE;
TCItem.item.pszText = sfi.szDisplayName;
TCItem.item.iImage = sfi.iIcon;
TCItem.item.iSelectedImage = sfi.iIcon;
TCItem.item.lParam = 0;
if(hItem == NULL)
{
TCItem.hParent = m_hRoot;
//hItemTmp = InsertItem(szFileName, m_hRoot);
hItemTmp = InsertItem(&TCItem);
}
else
{
TCItem.hParent = hItem;
//hItemTmp = InsertItem(szFileName, hItem);
hItemTmp = InsertItem(&TCItem);
}
TCHAR* pData = new TCHAR[strNextDir.GetLength()];
lstrcpy(pData, (LPCTSTR)strNextDir);
SetItemData(hItemTmp, (DWORD_PTR)pData);
InitTreeCtrl(strNextDir, hItemTmp);
}
}
Expand(m_hRoot,TVE_EXPAND);
finder.Close();
}
这种写法是比较常见的,这样写有什么问题呢?首先数据和逻辑混在一起;其次,每刷新一次,都要重新读取目录一次;再次,就是扩展性不好。这里是读取一个指定目录,那如果目录数据来源于数据库呢,又或者来源于服务程序?
所以,网上搜的资料,可以参考,可以借鉴,更要深入的思考和优化。
都提倡设计模式,但是说一套,做一套,并不是一个好的方式。有的人说起来一套套的,似乎这也会,那也懂,但是写的东西不是有内存泄露,就是导致程序异常。对于这种数据和逻辑混淆在一起的情况,其实大有存在。
先看看下面的代码:
int CFileTreeCtrl::InitData(int parentId, HTREEITEM hItem)
{
COprMySql OprMySql;
BOOL bFlag=FALSE;
TFile* temp;
int nData = m_file[parentId];
if (nData == 1)
{
Expand(hItem,TVE_EXPAND);
temp = m_fileData[parentId];
((CDlgUpFile*)(GetParent()))->m_EditPath.SetWindowText(temp->url);
return 1;
}
vector<TFile> tFile;
tFile.empty();
vector<TFile>::iterator iter;
char strtemp[20];
OprMySql.QueryFileSqlByParentId(tFile, parentId);
for(iter=tFile.begin(); iter!=tFile.end(); iter++)
{
temp = new TFile();
*temp = *iter;
TV_INSERTSTRUCT TCItem;
ZeroMemory(&TCItem,sizeof(TV_INSERTSTRUCT));
TCItem.hInsertAfter = TVI_LAST;
TCItem.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_STATE|TVIF_SELECTEDIMAGE;
TCItem.item.pszText = temp->name.GetBuffer();
//TCItem.item.iImage = sfi.iIcon;
//TCItem.item.iSelectedImage = sfi.iIcon;
TCItem.item.lParam = temp->id;
TCItem.hParent = hItem;
InsertItem(&TCItem);
m_fileData[temp->id] = temp;
}
OprMySql.Close();
m_file[parentId] = 1;
Expand(hItem,TVE_EXPAND);
temp = m_fileData[parentId];
((CDlgUpFile*)(GetParent()))->m_EditPath.SetWindowText(temp->url);
return 0;
}
这段代码是从数据库获取目录信息,参数parentId,是表示选中的级数,一般默认加载一级的,当选中某个的时候,就在查询数据库获取它的子项,在这里做了一个标记,m_file[parentId],第一次从数据库获取后,就设置m_file[parentId]=1,同时保存节点的信息m_fileData[temp->id] = temp。
而如果换成一个目录的话,只需要把这一句:OprMySql.QueryFileSqlByParentId(tFile, parentId);里的函数查询数据库,改成本地文件路径的数据。
这是初始的数据,当有增加和删除操作的时候,也一样。同时更新数据库和map的数据就好。
同样的道理,对于CListCtrl里的数据也是如此。
转载请注明原创链接:http://blog.csdn.net/wujunokay/article/details/13278131