5

我想要将标准的 Windows 信息(以及警告和错误)图标绘制到 pagecontrol 选项卡的索引上。但是,如果 Windows 背景颜色不是白色,则结果看起来很糟糕。

program Project111;

uses
  Vcl.Forms,
  Vcl.Controls,
  Vcl.Graphics,
  Winapi.Windows,
  Vcl.ComCtrls,
  Vcl.ImgList;

{$R *.res}

var
  mainForm: TForm;
  imageList: TImageList;
  icon: TIcon;
  pageControl: TPageControl;
  tabSheet: TTabSheet;
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;

  Application.CreateForm(TForm, mainForm);

  imageList := TImageList.Create(mainForm);
  imageList.ColorDepth := cd32bit;
  icon := TIcon.Create;
  try
    icon.Handle := LoadImage( 0, IDI_INFORMATION, IMAGE_ICON, 16, 16, {LR_DEFAULTSIZE or} LR_SHARED );
    imageList.AddIcon(icon);
  finally
    icon.Free;
  end;

  pageControl := TPageControl.Create(mainForm);
  pageControl.Parent := mainForm;
  pageControl.Images := imageList;

  tabSheet := TTabSheet.Create(mainForm);
  tabSheet.Parent := pageControl;
  tabSheet.PageControl := pageControl;
  tabSheet.ImageIndex := 0;

  Application.Run;
end.

这是一个屏幕截图: 在此处输入图像描述

正如你所看到的白色边框是模糊的,我猜这是因为 TImageList 缺乏适当的 alpha 透明度,但我不知道如何解决这个问题。

该解决方案不必使用 TImageList,我很乐意使用任何其他方法。请注意,还会有标题,并非所有索引都有图标,并且图标可能会随着上下文的变化而更改/添加/删除。

我正在使用 Delphi XE-2,如果有帮助的话,我也有 DevExpress 组件。

4

2 回答 2

6

正如@Sertac 所说,您看到的是将 Windows shell 图标从 32x32 调整为 16x16 的效果,作为从 Windows Vista 开始的解决方法,您可以使用该SHGetStockIconInfo功能。传递SHGSI_SMALLICON标志以检索图标的小版本,由SM_CXSMICONand指定SM_CYSMICON

的值SM_CXSMICONSM_CYSMICON取决于当前 DPI 设置。对于 DPI 96 是16x16

样本

  LIcon := TIcon.Create;
  try
    LIcon.Handle := 0;
    if TOSVersion.Check(6, 0) then
    begin
      ZeroMemory(@LSHStockIconInfo, SizeOf(LSHStockIconInfo));
      LSHStockIconInfo.cbSize := sizeof(LSHStockIconInfo);
      if SHGetStockIconInfo(SIID_INFO, SHGSI_ICON or SHGSI_SMALLICON, LSHStockIconInfo) = S_OK then
      begin
        LIcon.Handle := LSHStockIconInfo.hIcon;
        imageList.AddIcon(LIcon);
      end;
    end;
  finally
    LIcon.Free;
  end;
于 2017-11-28T04:02:41.280 回答
3

您看到的不是因为 alpha 透明度损坏,而是因为调整大小的工件。

文档LoadImage所述,图标加载的默认大小为SM_CXICONx SM_CYICON,通常为 32x32。由于您正在请求系统共享的图标,因此这将是给出的图标的大小。

您可以验证您的代码中是否存在这种情况:

  ..
  try
    icon.Handle := LoadImage( 0, IDI_INFORMATION, IMAGE_ICON, 16, 16, {LR_DEFAULTSIZE or} LR_SHARED );
    Assert(icon.Width = GetSystemMetrics(SM_CXICON));
    Assert(GetSystemMetrics(SM_CXICON) <> 16);
    ..

接下来是图标调整大小以适应图像列表可能没有比StretchBlt使用COLORONCOLOR模式更好的了。

不幸的是,无法加载非标准尺寸的系统图标,因为再次记录,

加载系统图标或光标时,必须使用LR_SHARED否则该函数将无法加载资源。


您需要做的是使用其默认大小加载共享图标,然后使用更好的算法自己将其调整为 16x16。StretchBltwithHALFTONE可能会更好,但使用更高级的图形库可以产生最佳结果。

强烈建议不要直接从资源所在的位置加载资源。如果您不使用该LR_SHARED标志,您将获得请求的大小。您需要做一些研究才能找到图标的实际索引,因为这没有记录。并且需要考虑索引或它所在的位置可能会及时更改。在这种情况下不要忘记自己销毁图标,因为系统不会为非共享资源执行此操作。

icon.Handle := LoadImage(GetModuleHandle(user32), Pointer(104), IMAGE_ICON, 16, 16, 0);
于 2017-11-28T01:18:12.243 回答