end;
在NewBrowseProc中必须处理几条消息。第一个就是用户在ComboBox中选择一项的时候,在TreeView中必须同步跳转到同样的文件夹:
case uMsg of
WM_COMMAND:
if HiWord(wp)=CBN_SELCHANGE then begin
hCombo := GetDlgItem(AWnd, IDC_COMBO);
index := SendMessage(hCombo, CB_GETCURSEL, 0, 0);
if index=CB_ERR then Exit;
csidl := SendMessage(hCombo, CB_GETITEMDATA, index, 0);
if csidl<>555 then begin // csidl
SHGetSpecialFolderLocation(AWnd, csidl, pidl);
SendMessage(AWnd, BFFM_SETSELECTION, 0, LongInt(pidl));
CoTaskMemFree(pidl);
end
else begin // normal Folder
SetLength(str, MAX_PATH);
SendMessage(hCombo, CB_GETLBTEXT, index, LongInt(PChar(str)));
str := PChar(str);
SendMessage(AWnd, BFFM_SETSELECTION, 1, LongInt(PChar(str)));
end;
end;
由于我们添加的ComboBox是一个自绘风格(Owner-Draw)的列表,所以我们还必须处理WM_MEASUREITEM和WM_DRAWITEM消息。WM_MEASUREITEM的处理相对简单,因为对于ComboBox来说项目的宽度无所谓(它自动由ComboBox本身的宽度来决定),我们只需要设置它的高度即可。为了简化起见,我用了硬编码的方法,当然基于系统设置进行仔细的计算也是可行的(而且完全应该):
WM_MEASUREITEM:
begin
pmis := PMEASUREITEMSTRUCT(lp);
if pmis^.CtlType=ODT_COMBOBOX then
pmis^.itemHeight := 20;
end;
其中pmis声明为一个PMEASUREITEMSTRUCT结构指针。
WM_DRAWITEM的处理要复杂的多。因为对于系统级的文件夹,必须从System ImageList中获得它的图标,而且还要从LPITEMIDLIST取得文件夹的名称(不一定是文件路径:比如,c:\windows\desktop在Shell中的名称是“桌面”)。为此我添加了几个辅助函数,用来简化WM_DRAWITEM的处理:
function GetNameFromPIDL(pidl:PItemIDList) : string;
var
sfi : SHFILEINFO;
begin
SHGetFileInfo(PChar(pidl), 0, sfi, sizeof(sfi), SHGFI_DISPLAYNAME or SHGFI_PIDL);
Result := StrPas(sfi.szDisplayName);
end;
function GetPathFromPIDL(pidl:PItemIDList) : string;
var
str : string;
begin
SetLength(str, MAX_PATH);
SHGetPathFromIDList(pidl, PChar(str));
str := PChar(str);
Result := str;
end;
procedure GetSmallIconFromPIDL(pidl:PItemIDList; var iml:HIMAGELIST; var index:integer);
var
sfi : SHFILEINFO;
begin
iml := SHGetFileInfo(PChar(pidl), 0, sfi, sizeof(sfi), SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_PIDL);
index := sfi.iIcon;
end;
procedure GetSmallIconFromPath(const Path:string; var iml:HIMAGELIST; var index:integer);
var
sfi : SHFILEINFO;
begin
iml := SHGetFileInfo(PChar(Path), 0, sfi, sizeof(sfi), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
index := sfi.iIcon;
end;
处理项目绘制的代码其实从原理上来讲非常简单,但是比较琐碎,必须大量调用SendMessage和Shell API接口函数,还包括GDI对象的管理。我不打算仔细解释下面这些代码;这些代码的效果就是在ComboBox中为每一个项目前面添加一个代表其文件夹的图标。
WM_DRAWITEM:
begin
pdis := PDRAWITEMSTRUCT(lp);
if pdis^.CtlType=ODT_COMBOBOX then begin
hCombo := pdis^.hwndItem;
if pdis^.itemID=$ffffffff then Exit;
csidl := DWORD(SendMessage(hCombo, CB_GETITEMDATA, pdis^.itemID, 0));
if (pdis^.itemState and ODS_SELECTED)=ODS_SELECTED then begin
FillRect(pdis^.hDC, 上一页 [1] [2] [3] [4] 下一页 [常用软件]Window Media Player 播放器 [Delphi程序]Window SubClassing之另类运用(之一) [Delphi程序]override deal with window closing in database … [Delphi程序]Window 消息大全使用详解 [网页制作]Chromeless Window For IE6 SP1 [网页制作]关于Web设计、开发中window对象的资料 [Web开发]JavaScript : WINDOW FOR JAVASCRIPT [Web开发]JavaScript关于window.open()应用 [Web开发]关于Web设计、开发中window对象的资料 [Web开发]Javascript:window对象的方法
|