饥荒传送代码不能用:DELPHI中图标应用的一些代码

来源:百度文库 编辑:九乡新闻网 时间:2024/05/06 15:43:12
在应用程序的编写中,组合框(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属性达到目的,归纳如下:

使用组件
设置代码示例
说明

组合框 
ComboBox1.Style:=csOwnerDrawVariable
根据实际使用经验最好不要在Object Inspector窗体中直接设置,而应将代码添加在程序的适当位置,否则可能出现绘图区域高度的不规则变化

列表框
ListBox1.Style:=lbOwnerDrawVariable

状态栏
StatusBar1.Panels.Style:= psOwnerDraw
不能使用简单状态栏,i是状态栏中要绘制图标的某一窗格索引号


图形输出可使用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环境下动态地使用图标是很灵活的,方法有多种,但图标的获取是关键,其次是图形的绘制。除了树状视图等可以直接显示图标的组件外,组合框、列表框、状态栏等不能直接显示图标的组件可以使用绘图的方法显示图标和文本。
 ---- 但是,当我们用可视化编程工具进行Windows编程时,却很少有方便的方法来加载和显示图标。一般来说,在我们的应用程序中使用到图标资源时都是我们自己亲自绘制出来的。因此,在我们编的程序中使用到的图标是很有限的。我们知道Windows中有大量已知的系统图标,如文件夹的图标、磁盘驱动器的图标等等。熟悉Windows编程的朋友也许知道这些图标在Windows内部是有其特定的编号的,只要获取了这些编号就能够调用并显示对应的图标了。通过比较,我选择了Delphi中的ListView组件来显示图标,因为这种方法是最简单的。

---- 下面是一个例子,该程序在Delphi 4.0中编译通过。

---- 该演示程序可以显示各类Windows系统图标,包括文件图标、磁盘图标、文件夹图标、用户特定可执行文件图标(如:Delphi的火炬图标等等)。有趣的是,我们显示的这些图标没有一个需要我们自己亲自动手绘制。

---- 请先在Delphi环境下建立一个窗体Form1,并在Form1中添加一个按钮Button1和一个列表框ListView1;然后请设置ListView1的属性ViewStyle为vsIcon。

---- 源程序清单:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils,
Classes, Graphics, Controls,
  Forms, Dialogs, ComCtrls,
StdCtrls, ShellAPI, ExtCtrls,
  ImgList;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Button1: TButton;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  Test='C:\';
  { Test为测试数据,在本例中返回的是一个驱动器图标。读者
    可以自行选择其他测试数据如:Test:='C:\Autoexec.bat'
    等等。}

var
  Form1: TForm1;
  ShFileInfo: TSHFILEINFO;

implementation

{$R *.DFM}
function GetFileIconIndex
(FileName:string):integer;
  { 获取图标的序号函数 }
var
  Ext:String;
begin
  Ext:=FileName;
  Result:=ShGetFileInfo(Pchar
(Ext), 0, SHFileInfo,
          SizeOf(SHFileInfo), SHGFI_LARGEICON or
        SHGFI_SYSICONINDEX or SHGFI_TYPENAME);
  Result:=SHFileInfo.iIcon;
  { 返回获取的图标序号 }
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  with ListView1 do
    begin
      SmallImages:=TImageList.CreateSize(32,32);
      SmallImages.ShareImages:=True;
      SmallImages.Handle:=ShGetFileInfo('*.*',0,
SHFileInfo, SizeOf(SHFileInfo),
SHGFI_LARGEICON or
SHGFI_ICON or SHGFI_SYSICONINDEX);
      LargeImages:=TImageList.CreateSize(32,32);
      LargeImages.ShareImages:=True;
      LargeImages.Handle:=ShGetFileInfo('*.*',0,
SHFileInfo, SizeOf(SHFileInfo),
SHGFI_LARGEICON or
SHGFI_ICON or SHGFI_SYSICONINDEX);
    end;
{ 分配系统资源给ListView1组件以显示图标 }
end;

procedure TForm1.FormDestroy
(Sender: TObject);
begin
  ListView1.SmallImages.Free;
  ListView1.LargeImages.Free;
  { 释放ListView1占用的系统资源 }
end;

procedure TForm1.Button1Click
(Sender: TObject);
begin
  ListView1.Items.Item[0].
ImageIndex:=GetFileIconIndex(Test);
  { 为ListView1中的第一个项目绘制图标 }
end;

end.  如何把图标文件转换为位图文件 
    图 标 和 位 图 是WINDOWS 中 常 见 的 两 种 图 形 资 源, 在 开 发 应 用 程 序 时, 充 分 地 运 用 这 些 资 源 可 以 极 大 地 改 进 程 序 的 界 面, 增 强 软 件 的 实 现 效 果。 例 如 在DELPHI 中, 我 们 可 以 给 应 用 指 定 一 个 图 标, 给 位 图 命 令 按 钮 或 加 速 按 钮 指 定 一 个 位 图 等。 许 多 开 发 工 具 都 提 供 有 大 量 的 图 形 资 源, 包 括 位 图、 图 标、 光 标、 视 频 文 件 等, 比 如 在DELPHI、Visual Basic 5.0 中 就 提 供 有 大 量 的 位 图 和 图 标, 但 并 不 是 所 有 图 标 都 有 相 应 的 位 图 文 件, 有 时 我 们 有 使 用 位 图 文 件 时, 会 觉 得 某 个 图 标 的 图 形 更 合 适, 但 却 没 有 相 应 的 位 图 文 件 可 以 使 用, 例 如DELPHI 中 的 位 图 按 钮, 其Glyph 属 性 用 于 指 定 显 示 在 按 钮 中 的 位 图, 但 该 属 性 只 能 使 用 位 图 文 件(.bmp), 而 不 能 使 用 图 标 文 件(.ico), 在 这 种 情 况 下, 我 们 就 需 要 把 图 标 文 件 转 换 为 位 图 文 件。

    利 用DELPHI 来 实 现 这 样 的 转 换 是 非 常 方 便 的,DELPHI 把Windows 的 位 图 及 其 调 色 板 封 装 在Tbitmap 类 中, 把Windows 图 标 封 装 在Ticon 中, 我 们 只 需 把Tbitmap 和Ticon 的 属 性 和 方 法 作 些 简 单 应 用, 就 可 以 实 现 图 标 文 件 到 位 图 文 件 的 转 换。

    下 面 的 小 程 序 可 实 现 图 标 文 件 到 位 图 文 件 的 转 换, 它 能 够 把 所 给 定 的 图 标 文 件 转 换 为 同 名 的 位 图 文 件, 程 序 中 只 是 简 单 地 通 过 程 序 扩 展 名 来 判 断 图 标 文 件 和 位 图 文 件。

    各 部 件 及 其 主 要 属 性 设 置 如 下:
部 件            属 性            属 性 值
Form1            Name            ‘Form1’
                  Caption          ‘ICO= >BMP’
StaticText1        Name            ‘StaticText1’
                Caption            ‘ 图 标 文 件:’
Edit1            Name            ‘Edit1’
                Text              ‘’
BitBtn_Browse    Name            ‘BitBtn_Browse’
                Caption            ‘ 浏 览...’
BitBtn_Convert    Name            ‘BitBtn_Convert’
                Caption            ‘ 转 换’
OpenDialog1      Name            ‘OpenDialog1’
                Filter              ‘ 图 标 文 件(*.ico)|*.ico’

    实 现 转 换 的 源 程 序 如 下 所 示:

unit main;
interface
  uses  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls, Buttons;

type
  TForm1 = class(TForm)
    StaticText1: TStaticText;
    BitBtn_Convert: TBitBtn;
    OpenDialog1: TOpenDialog;
    BitBtn_Browse: TBitBtn;
    Edit1: TEdit;
    procedure BitBtn_BrowseClick(Sender: TObject);
    procedure BitBtn_ConvertClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;

implementation
{$R *.DFM}
procedure TForm1.BitBtn_BrowseClick(Sender: TObject);
begin
  if opendialog1.Execute  then
    edit1.Text := opendialog1.filename; //读入的文件类型是*.ico
end;
procedure TForm1.BitBtn_ConvertClick(Sender: TObject);
var
Icon1:Ticon;
Bitmap1:Tbitmap;
FileName,FileExt:String;
begin
if FileExists(Edit1.Text) then
begin
  FileExt:= ExtractFileExt(Edit1.Text);
  if UpperCase(FileExt)=’.ICO’ then
  begin //*.ico-----> *.bmp
    FileName:=copy(edit1.text,0,pos(’.ico’,edit1.text)-1);
    icon1:=ticon.create;
    bitmap1:=tbitmap.create;
    icon1.loadfromfile(edit1.text);
    Bitmap1.Width := Icon1.Width;
    Bitmap1.Height := Icon1.Height;
    Bitmap1.Canvas.Draw(0, 0, Icon1 );
    Bitmap1.SaveToFile(FileName+’.bmp’);
    Icon1.Free;
    Bitmap1.Free;
    ShowMessage(’文件转换成功!’);
  end
  else
    ShowMessage(’所给定的文件不是图标文件!’);
end
else
  ShowMessage(’所给文件不存在!’);

end;
end.