【问题标题】:How to draw transparent bitmap from ImageList on TMenuItem?如何从 TMenuItem 上的 ImageList 绘制透明位图?
【发布时间】:2019-01-15 18:34:35
【问题描述】:

我需要在 TMenuItem 上绘制透明位图。尽管用不同的方法尝试了很多小时,但我还是没有成功:

var
  NewItem: TMenuItem;
  ThisBmp: TBitmap;
begin
  NewItem := TMenuItem.Create(pmSendToCustomTool);
  NewItem.Caption := ThisCaption;
  NewItem.Bitmap.SetSize(16,16);
  NewItem.Bitmap.PixelFormat := pf32bit;
  NewItem.Bitmap.Transparent := True;
  NewItem.Bitmap.TransparentColor := clFuchsia;
  ThisBmp := TBitmap.Create;
  try
    ThisBmp.SetSize(16,16);
    ThisBmp.PixelFormat := pf32bit;
    ThisBmp.Transparent := True;
    ThisBmp.Canvas.Brush.Color := clFuchsia;
    ThisBmp.TransparentColor := clFuchsia; 
    MySystemImageList1.GetBitmap(AIndex, ThisBmp);
    CodeSite.Send('ThisBmp', ThisBmp);
    NewItem.Bitmap.Assign(ThisBmp);
    CodeSite.Send('NewItem.Bitmap', NewItem.Bitmap);
  finally
    ThisBmp.Free;
  end;

这就是 ThisBmp 在 CodeSite 中 GetBitmap 之后的样子:

生成的菜单项如下所示:

【问题讨论】:

  • 您是否有理由不简单地使用TMenuItem.ImageIndex 属性?将您的 ImageList 分配给父菜单的 Images 属性或父菜单项的 SubMenuImages 属性(取决于您的 UI 设计),然后将菜单项的 ImageIndex 设置为所需的索引。让 ImageList 为您处理透明绘图。
  • 是的,这是有原因的。我必须这样做。原因:在弹出菜单中,我有一些从 SystemImageList(如上)获取字形的项目和从标准 TImageList 获取字形的其他项目。由于我只能对整个弹出菜单使用 ONE Imagelist,因此我必须以这种方式提取部分字形。
  • 实际上,你没有。您可以 1) 将所有图像复制到单个 TImageList,或 2) 所有者绘制菜单项,然后您可以从任何您想要的源进行绘制。您根本不必使用 Bitmap 属性。
  • 为什么要手动设置透明色?如果您将TBitmap.Transparent 设置为True 并且不为TransparentColor 设置任何值,则TBitmap 将使用左下图像像素作为透明颜色。还有你为什么要设置Brush.color

标签: delphi delphi-10.1-berlin tmenuitem


【解决方案1】:

您的代码不起作用,因为您在使用 GetBitmap() 时丢失了所有透明度信息。您将不得不手动绘制位图,例如:

uses
  ..., Winapi.CommCtrl;

procedure GetTransparentBitmapFromImageList(ImageList: TCustomImageList; Index: Integer; Bitmap: TBitmap);
var
  i: integer;
begin
  // make sure your ImageList is set to ColorDepth=cd32bit and DrawingStyle=dsTransparant beforehand...
  Bitmap.SetSize(ImageList.Width, ImageList.Height);
  Bitmap.PixelFormat := pf32bit;
  if (ImageList.ColorDepth = cd32Bit) then
  begin
    Bitmap.Transparent := False;
    Bitmap.AlphaFormat := afDefined;
  end
  else
    Bitmap.Transparent := True;
  for i := 0 to Bitmap.Height-1 do
    FillChar(Bitmap.ScanLine[i]^, Bitmap.Width*SizeOf(DWORD), $00);
  ImageList_Draw(ImageList.Handle, Index, Bitmap.Canvas.Handle, 0, 0, ILD_TRANSPARENT);
end;

或者:

procedure GetTransparentBitmapFromImageList(ImageList: TCustomImageList; Index: Integer; Bitmap: TBitmap);
begin
  Bitmap.PixelFormat := pf32bit;
  Bitmap.Canvas.Brush.Color := clFuschia;
  Bitmap.SetSize(ImageList.Width, ImageList.Height);
  ImageList.Draw(Bitmap.Canvas, 0, 0, AIndex, dsTransparent, itImage);
  Bitmap.Transparent := True;
  Bitmap.TransParentColor := clFuchsia;
  Bitmap.TransparentMode := tmAuto;
end;

那么你可以这样做:

var
  NewItem: TMenuItem;
begin
  NewItem := TMenuItem.Create(pmSendToCustomTool);
  NewItem.Caption := ThisCaption;
  GetTransparentBitmapFromImageList(MySystemImageList1, AIndex, NewItem.Bitmap);
  CodeSite.Send('NewItem.Bitmap', NewItem.Bitmap);
end;

【讨论】:

  • 谢谢 Remy,但是当我使用 Alternatively 下的方法时,我得到了这个结果:i.imgur.com/YPTlgVM.png
  • ...而且第一个版本也不起作用。这是第一个版本的结果(不透明的颜色现在是黑色而不是紫红色):i.imgur.com/XVFqnsn.png
  • 唯一剩下的可能性是将图像从 SystemImageList 复制到与弹出菜单关联的图像列表中。在保持透明度的同时如何做到这一点?然后我可以轻松地为所有弹出菜单项设置ImageIndex 属性。
猜你喜欢
  • 2012-07-20
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多