首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Delphi 動態圖示實作:SHGetFileInfo 取得系統關聯圖示、ImageList 載入與 OwnerDraw 繪製

     編輯:更多程式設計知識

三大步驟

  1. 取得圖示控制碼:`SHGetFileInfo` 依副檔名/檔案屬性從系統登錄取得圖示。
  2. 載入至 ImageList:`ImageList_AddIcon` 將 `HICON` 加入 `TImageList`,取得索引。
  3. OwnerDraw 繪製:對 `ComboBox`、`ListBox`、`ListView` 等設定 `Style = csOwnerDrawVariable`/`lbOwnerDrawVariable`,在 `OnDrawItem` 事件中用 `ImageList.Draw` + `Canvas.TextOut` 繪製圖示+文字。

核心 API 宣告 (ShellAPI)

function SHGetFileInfo(pszPath: PAnsiChar; dwFileAttributes: DWORD;
    var psfi: TSHFileInfo; cbFileInfo: UINT; uFlags: UINT): DWORD; stdcall;

type
  TSHFileInfo = record
    hIcon: HICON;           // 圖示控制碼
    iIcon: Integer;         // 系統映像清單索引
    dwAttributes: DWORD;    // 檔案屬性
    szDisplayName: array[0..MAX_PATH-1] of AnsiChar;  // 顯示名稱
    szTypeName: array[0..79] of AnsiChar;             // 類型名稱
  end;

常用 Flags 組合

Flag用途
SHGFI_ICON取得圖示控制碼
SHGFI_SMALLICON / SHGFI_LARGEICON小圖示(16x16) / 大圖示(32x32)
SHGFI_DISPLAYNAME取得顯示名稱 (含長檔名)
SHGFI_TYPENAME取得類型描述 (如 "Text Document")
SHGFI_USEFILEATTRIBUTES不需實體檔案存在,僅依屬性/副檔名取得通用圖示

完整範例:列出目錄檔案並顯示圖示 (ListBox OwnerDraw)

procedure TForm1.LoadFiles(const Dir: string);
var
  SR: TSearchRec;
  FI: TSHFileInfo;
  Idx: Integer;
begin
  ListBox1.Clear;
  ImageList1.Clear;
  ImageList1.Width := 16; ImageList1.Height := 16;  // 小圖示

  if FindFirst(IncludeTrailingPathDelimiter(Dir) + '*.*', faAnyFile, SR) = 0 then
  repeat
    if (SR.Attr and faDirectory) = 0 then begin  // 僅檔案
      // 1. 取得圖示
      SHGetFileInfo(PAnsiChar(Dir + SR.Name), 0, FI, SizeOf(FI),
          SHGFI_ICON or SHGFI_SMALLICON or SHGFI_DISPLAYNAME);
      // 2. 加入 ImageList
      Idx := ImageList_AddIcon(ImageList1.Handle, FI.hIcon);
      // 3. 加入 ListBox (儲存索引於 Objects)
      ListBox1.Items.AddObject(FI.szDisplayName, TObject(Idx));
      DestroyIcon(FI.hIcon);  // 釋放系統資源
    end;
  until FindNext(SR) <> 0;
  FindClose(SR);
end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
    Rect: TRect; State: TOwnerDrawState);
var
  Lb: TListBox;
  Idx: Integer;
begin
  Lb := Control as TListBox;
  Lb.Canvas.FillRect(Rect);
  Idx := Integer(Lb.Items.Objects[Index]);
  // 繪製圖示
  ImageList1.Draw(Lb.Canvas, Rect.Left + 2, Rect.Top + 1, Idx);
  // 繪製文字
  Lb.Canvas.TextOut(Rect.Left + 20, Rect.Top + 1, Lb.Items[Index]);
end;

進階技巧

  • 大圖示模式:`ImageList.Width/Height := 32`,`SHGFI_LARGEICON`,`ListView` 設 `ViewStyle = vsIcon`。
  • 虛擬資料夾 (我的電腦、網路芳鄰) 需 `SHGFI_PIDL` 配合 `SHGetFolderLocation`/`SHBindToParent` 取得 PIDL,較複雜。
  • 快取系統映像清單**:`SHGetFileInfo` 配合 `SHGFI_SYSICONINDEX` 直接取得系統 `ImageList` 索引,避免重複載入,但需處理進程間共用映像清單。
  • 高 DPI**:VCL 高 DPI 感知下,`ImageList` 需對應縮放比例 (96/120/144 DPI) 準備多尺寸圖示。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved