在Delphi中使用动态图标
在应用程序的编写中,组合框(ComboBox)、列表框(ListBox)、树状视图(TreeView)、列表视图(ListView)等常见的列表部件,通常不仅要显示文字,而且要显示其与文字相关的图标,一般在Windows的应用程序中,这些图标的显示都要随列出的显示文本的变化而变化。例如在组合框中列出当前目录下的所有文件时,在其组合框的左边显示与文件名相关联的图标,这就是所谓的动态图标。 一、图标的获取 要使用动态图标,首先要解决的是如何获得显示文本和与显示文本相关联的图标句柄,该图标通过文件关联由统注册表决定,并且在Windows编程中同一文件(或子目录,或文件夹)在桌面上也可能有两种显示结果,这就是DOS文件名与显示名(Display Name)。如果我们的应用程序不需要有象windows资源浏览器那样的效果,则可以使用FindFirst()和FindNext()二个函数以及FindClose()过程来获得DOS文件名,否则我们就应当使用WindowsAPI来获得显示名。在获得文件名的同时可通过使用ShellAPI.pas中的SHGetFileInfo()函数来获得其图标句柄HICON,说明如下。 function SHGetFileInfo( pszPath: PAnsiChar; dwFileAttributes: DWORD; var psfi: TSHFileInfo; cbFileInfo, uFlags: UINT ): DWORDl; pszPath 参数:指定的文件名。当uFlags的取值中不包含 SHGFI_PIDL时, 可直接指定;当uFlags的取值中包含 SHGFI_PIDL时pszPath要通过计算获得,不能直接指定; dwFileAttributes参数:文件属性,仅当uFlags的取值中包含SHGFI_USEFILEATTRIBUTES时有效,一般不用此参数; psfi 参数:返回获得的文件信息,是一个记录类型,有以下字段: hIcon: HICON; //文件的图标句柄 iIcon: Integer; //图标的系统索引号 dwAttributes: DWORD; //文件的属性值 szDisplayName: array [0..MAX_PATH-1] of AnsiChar; //文件的显示名 szTypeName: array [0..79] of AnsiChar; //文件的类型名 cbFileInfo 参数:psfi的比特值; uFlags 参数:指明需要返回的文件信息标识符,常用的有以下常数: SHGFI_ICON; //获得图标 SHGFI_DISPLAYNAME; //获得显示名 SHGFI_TYPENAME; //获得类型名 SHGFI_ATTRIBUTES; //获得属性 SHGFI_LARGEICON; //获得大图标 SHGFI_SMALLICON; //获得小图标 SHGFI_PIDL; // pszPath是一个标识符 函数SHGetFileInfo()的返回值也随uFlags的取值变化而有所不同。 可见通过调用SHGetFileInfo()可以由psfi参数得到文件的图标句柄。但要注意在uFlags参数中不使用SHGFI_PIDL时,SHGetFileInfo()不能获得“我的电脑”等虚似文件夹的信息。 二、图标的加载 使用Delphi提供的TImageList组件,通过调用CommCtrl .pas中的函数ImageList_AddIcon()来加载得到的图标,并要保证其索引号与显示文本相对应。说明如下。 function ImageList_AddIcon( ImageList: HIMAGELIST; //加载图标的ImageList句柄 Icon: Hicon //加载的图标句柄 ): Integer; {返回图标在ImageList中的索引号 在需要指明图标索引号时可使用ImageList_AddIcon()的返回值} 三、图标和文本的绘图式输出 对于组合框、列表框等不能直接显示图标的组件,由于要显示图标又要同时显示文本,所以在一次显示刷新中不能使用直接的文本输出来显示文本,而要使用绘图的方式显示图标和文本,可通过设置其相应的Style属性达到目的,归纳如下:
图形输出可使用TImageList的ImageList1.Draw()方法,而文本输出则可使用TCanvas的TextOut()方法,它由组件的Canvas属性继承得到,显然没有Canvas属性的组件不能使用此方法显示图标。 对于树状视图、列表视图等可直接显示图标的组件,直接指定其Images、StateImages等需要的图标属性为相应的ImageList名,并通过图标的索引号指定则可显示图标。需要注意的是在使用大图标时,必须先调用TImageList的CreateSize()方法指定可加载图标的尺寸,并且在每次调用TImageList的Clear方法后都要重新调用CreateSize()。 使用TImageList的ImageList1.Clear方法清除已加载的图标,常在需要刷新时使用。 四、实例说明 下面以组合框(ComboBox)为例,说明上述方法。 1.
运行Delphi并创建一个新工程; 2.
在Form1上面添加二个元件:
ImageList1和ComboBox1; 3.
选择Form1, 并在Object
Inspector窗体中选择Events页的OnCreate事件,编写Form1的OnCreate事件过程如下: procedure TForm1.FormCreate(Sender: TObject); var FS:TSearchRec; icon
:HICON; path:String; begin //获得C:盘根目录下的所有文件名和子目录 path:='c:\'; FindFirst(path+'*.*',faDirectory
,FS); icon:=GetIcon(path+FS.Name); ImageList_AddIcon(ImageList1.Handle,icon); ComboBox1.Items.Add(FS.Name); while
FindNext(FS)=0 do
begin
icon:=GetIcon(path+FS.Name);
ImageList_AddIcon(ImageList1.Handle,icon );
ComboBox1.Items.Add(FS.Name);
end; FindClose(FS); ComboBox1.ItemIndex:=0; ComboBox1.Style:=csOwnerDrawVariable; end; 其中GetIcon()是一个自定义函数,代码清单如下: function TForm1.GetIcon(fName:String): hicon; //获得fName的图标句柄 const Flags
= SHGFI_ICON or SHGFI_SMALLICON; var FileInfo:
TSHFileInfo; Begin SHGetFileInfo(PChar(fName),
0,
FileInfo,
SizeOf(FileInfo),
Flags); Result
:= FileInfo.hIcon ; end; 4.
选择ComboBox1,并在Object
Inspector窗体中选择Events页的OnDrawItem事件,编写ComboBox1的OnDrawItem事件过程如下: procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); begin
ComboBox1.Canvas.FrameRect(Rect);
//在组合框中绘制图标
ImageList1.Draw(ComboBox1.Canvas,
Rect.Left+5,
Rect.Top,
Index,
true);
//在组合框中绘制文本
ComboBox1.Canvas.TextOut(Rect.Left+30,
Rect.Top,
ComboBox1.Items.Strings[Index]); end; 5.
在Unit1.pas文件的interface后的uses中添加ShellApi和CommCtrl。 运行该工程我们就会看到在Form1上有一个显示动态图标的组合框,本例在Delphi
4中完成。 五、小结 在Windows环境下动态地使用图标是很灵活的,方法有多种,但图标的获取是关键,其次是图形的绘制。除了树状视图等可以直接显示图标的组件外,组合框、列表框、状态栏等不能直接显示图标的组件可以使用绘图的方法显示图标和文本。 |
|||||||||||||
回复Comments
{commenttime}{commentauthor}
{CommentUrl}
{commentcontent}