用樹型控制展現Win95注冊庫
發表于:2007-07-14來源:作者:點擊數:
標簽:
王惠民 樹型控制是Win 95支持的公共控制之一,功能極強,對多數事件的響應都是自動實現的。如果 使用它來 開發 訪問像Win 95注冊庫這樣具有層次結構的復雜程序,則能夠讓您省事不少。有關樹型控制及Win 95注冊庫本身的一些知識,請參考聯機文擋。本文著重介
王惠民
樹型控制是Win 95支持的公共控制之一,功能極強,對多數事件的響應都是自動實現的。如果 使用它來
開發訪問像Win 95注冊庫這樣具有層次結構的復雜程序,則能夠讓您省事不少。有關樹型控制及Win 95注冊庫本身的一些
知識,請參考聯機文擋。本文著重介紹采用樹型控制展現Win 95注冊庫的有關實現方法及遇到問題時的處理過程。
一、加入樹型控制和像表小位圖
首先,建立以對話框為基礎的主應用程序。然后,在其對話框資源中加入樹型控制??晒┻x擇的樹型控制的風格屬性(Styles)有:按鈕(樹中出現具有支持展開或收縮樹層的功能的+或-操作按鈕,對下面的風格屬性可作類似理解)、連接線、線在根處等等。最后,加入樹型控制的對應成員。例如:
CTreeCtrl m_TREECtrlREG;
像表小位圖用來表示對樹上的注冊庫關鍵字或子關鍵字被操作的狀態,是可選的。為簡單起見,可只用兩幅小位圖來區分有或無子關鍵字的關鍵字:一幅用來表示是有子關鍵字的關鍵字(類似于目錄),另外一幅用來表示是無子關鍵字的關鍵字(類似于文件)。小位圖的寬為15,高為16。
以上具體操作過程從略。
二、 最頂層和六個主層關鍵字名插入樹
在對話框的初始化函數OnInitDialog()中適宜做此工作,通過OnInitRootKey()函數來實現:
BOOL CWRegTreeCtrlDlg::OnInitDialog()
{ ......
//Add extra initialization here
//像表小位圖的建立
CImageList* pMyIL = new CImageList();
pMyIL->Create(16, 15, TRUE, 3, 2);
CBitmap MyBmp;
for(UINT nIndef=IDB_BMPBEG;
nIndef<=IDB_BMPEND; nIndef++)
{ MyBmp.LoadBitmap(nIndef);
pMyIL->Add(&MyBmp, (COLORREF)0xFFFFFF);
MyBmp.DeleteObject();
}
m_TREECtrlREG.SetImageList(pMyIL, TVSIL_NORMAL);
//最頂層和六個主層關鍵字名插入樹子函數
OnInitRootKey();
return FALSE;
}
VOID CWRegTreeCtrlDlg::OnInitRootKey()
{ ......
//全部清除樹視圖
m_TREECtrlREG.DeleteAllItems();
//建立初始樹視圖:最頂層和六個主層
TV_INSERTSTRUCT TreeCtrlItem;//樹控制項
TreeCtrlItem.hParent = TVI_ROOT;//最頂層
TreeCtrlItem.hInsertAfter = TVI_LAST;
TreeCtrlItem.item.iImage = 1;//目錄
TreeCtrlItem.item.iSelectedImage = 1;
TreeCtrlItem.item.mask=TVIF_IMAGE|TVIF_SELECTEDIMAGE| TVIF_TEXT|TVIF_CHILDREN;
TreeCtrlItem.item.pszText =_T(strTemp0.GetBuffer(20));
//“<我的電腦>頂層”
//插入樹根
hTreeItem[0]=m_TREECtrlREG.InsertItem(&TreeCtrlItem);
TreeCtrlItem.hParent =hTreeItem[0];//第一主層
TreeCtrlItem.hInsertAfter = TVI_LAST;
TreeCtrlItem.item.iImage = 1;
TreeCtrlItem.item.iSelectedImage = 1;
TreeCtrlItem.item.mask=TVIF_IMAGE|TVIF_SELECTEDIMAGE| TVIF_TEXT|TVIF_CHILDREN;
TreeCtrlItem.item.pszText =_T(rStr.GetBuffer(18) );
//“HKEY_CLASSES_ROOT”
//插入樹根
hTreeItem[1]= m_TREECtrlREG.InsertItem(&TreeCtrlItem);
//插入第二到第六主層與插入第一主層“HKEY_CLASSES_ROOT”的代碼類似,具體代碼從略
//展開最頂層
m_TREECtrlREG.Expand(hTreeItem[0],TVE_E
XPAND);
hCurItem=hTreeItem[0];
......
//訪問注冊庫時最頂層和主層位置路徑句柄的初值
hKeyRoot = 0;
return;
}
三、用鼠標單擊+或-按鈕或者雙擊樹項關鍵字名操作的響應
在樹上插入與顯示注冊庫各子關鍵字,是在用戶用鼠標單擊了+或-按鈕或者雙擊了樹項關鍵字名的操作響應過程中動態完成的。由于樹型控制的功能極強,所以幾乎沒有必要做管理樹型控制的工作(例如,視圖滾動等),只需編寫出響應上述操作的代碼就可以了。
VOID CWRegTreeCtrlDlg::OnDblclkTreereg(NMHDR*
pNMHDR,
LRESULT* pResult)
{ HTREEITEM hIT =
m_TREECtrlREG.GetSelectedItem( );
if( hCurItem != hIT) { hCurItem = hIT; }
SelectItemTr = m_TREECtrlREG.GetItemText(hIT);
//1.單擊了“<我的電腦>頂層”后的處理--交樹型控制處理
CString MainName ,strTemp0,strTemp1;
strTemp0.LoadString(IDS_STRINGPROMPT0);
strTemp1.LoadString(IDS_STRINGPROMPT1);
if( hIT == hTreeItem[0])
{//將初值放到其它各個控制中
......
//路徑,頂層句柄初始化
lpRegPath=_T("");
hKeyRoot = 0;
* pResult=0;
return;
}
//2.單擊了六個主層關鍵字名之一后的處理
if( OnIsMianItem(hIT) )
{//主層位置是否改變
if(m_TOPPOSOUT != SelectItemTr)
{m_TOPPOSOUT = _T("");
m_TOPPOSOUT = SelectItemTr;
}
//將初值放到其它各個控制中
......
//路徑,頂層句柄初始化
lpRegPath=_T(""); hKeyRoot = 0;
//新選擇的關鍵字名
m_CURKEYNAME=SelectItemTr;
//調整訪問注冊庫句柄值hKeyRoot
OnMainKeyHandle(hIT,hKeyRoot);
HTREEITEM hChild =
m_TREECtrlREG.GetChildItem(hIT);
//已經展開過,則交樹型控制自己反轉
if( hChild != NULL )
{ EnumValueName(hKeyRoot);//顯示關聯值名
* pResult=0;
return ;
}
UpdateData(FALSE);
//沒有展開過,則通過訪問注冊庫動態展開子關鍵字
QueryKeyInfo ( hKeyRoot );
* pResult=0;
return ;
}
//3.子層情況
//3.1 選擇的名字是重復選擇
if(
SelectItemTr==lpRegPath.Right(SelectItemTr.GetLength( )))
{ * pResult=0; return; }
//3.2 按照選擇的關鍵字名在樹上找到它的父關鍵字的全路徑名字(不包含被選擇的關鍵字的名字)。如果不等于lpRegPath,則要修改lpRegPath
CString strParent,strPath;
strParent = SelectItemTr;
//在樹上形成該項目的全路徑名字,反復往上爬
while( ! OnIsMianItem(hIT) )//是否到達主層位置
{hIT = m_TREECtrlREG.GetParentItem(hIT);
strParent=
(LPCTSTR)m_TREECtrlREG.GetItemText(hIT);
if(OnIsMianItem(hIT) )
{
int pos;
if((pos=strPath.ReverseFind('\\')) != -1)
{CString strTemp00;
strTemp00=strPath.Left(strPath.GetLength()-1);
strPath=strTemp00;
break;
}
}
else//左加上路徑
{CString strTemp99;
strTemp99.Format(_T("%s\\%s"),strParent,strPath);
strPath=strTemp99;
}
}
//主關鍵字的位置是否改變
MainName=m_TREECtrlREG.GetItemText(hIT);
if( MainName != m_TOPPOSOUT)
{ m_TOPPOSOUT = _T("");
m_TOPPOSOUT = MainName;
//調整訪問注冊庫句柄值hKeyRoot
OnMainKeyHandle(hIT,hKeyRoot);
}
if( strPath != lpRegPath ) lpRegPath = strPath;
// 將初值放到其它各個控制中
......
//是否要刷新
HTREEITEM hChild3 = m_TREECtrlREG.GetChildItem( hCurItem );
HTREEITEM hTemp3;
while (hChild3 != NULL)
{ hTemp3 = m_TREECtrlREG.GetNextSiblingItem(hChild3);
m_TREECtrlREG.DeleteItem(hChild3);
hChild3 = hTemp3;
}
UpdateData(FALSE);
//展開一層,即在樹上插入與顯示子層的直接各子層關鍵字名字
//參數包括:被選擇的關鍵字名字,路徑(不包含被選擇的關鍵字名字),六個主關鍵字句柄之一
RegLevelExpand ( SelectItemTr,lpRegPath, hKeyRoot);
return ;
}
四、對目錄或文件的處理
注冊庫的子關鍵字的名字是動態插入到樹上的,首次插入到樹上的關鍵字的下面是否又有子關鍵字是不知道的,因此兩個像表小位圖也不能確定使用哪一個。在這點上,樹型控制也無能為力,它只能通過用戶指定插入項目的cChildren,iImage和iSelectedImage標志值為I_CHILDRENCALLBACK,而后在需要確定值時,通過控制向父窗口發送通知TVN_GE
TDISPINFO來取得需要的信息,但是樹型控制將+或-按鈕一律設置為+按鈕,顯然目錄和文件兩種位圖都被設置成了可展開的+按鈕,使用戶感到迷惑,從而失去了直觀性(關鍵字一旦展開過一次以后,樹型控制就可以區分它了!)。解決方法如下所述:
在訪問注冊庫時,對展開關鍵字再進行檢測(幸好注冊庫可以嵌套打開),檢測到是否有子關鍵字后立即返回,從而可以精確地確定+或-按鈕以及位圖的狀態,并且正確地插入到樹上,其它情況樹型控制均能夠自動處理。
//檢測函數入口,參數為:路徑,六個主關鍵字句柄之一
DWORD CWRegTreeCtrlDlg::RegLevelPreExpand(const
CString & lpRegSub, HKEY & hPreKey)
{ HKEY hKey; DWORD RetValue,SubKeyNs;
......
//1.獲得路徑的句柄
RetValue = (DWORD)RegOpenKeyEx (
(HKEY)hPreKey,LPCTSTR(lpRegSub),0,
(REGSAM) KEY_ENUMERATE_SUB_KEYS|
KEY_EXECUTE ,
(PHKEY)&hKey);//接收返回打開關鍵字的句柄
//2.打開是否成功檢測
......
//3.詢問子關鍵字數信息
SubKeyNs=QuerySubKeyNums (hKey);
//4.關閉注冊庫
RegCloseKey (hKey);
return SubKeyNs;
}
原文轉自:http://www.anti-gravitydesign.com