Delphi and 48x48 (or bigger) imagelists - is there a workaround?

6.3k views Asked by At

I'm getting the system imagelist (with SHGetFileInfo and SHGFI_LARGEICON), adding two of my own icons and attaching it to a TListView.

The problem is that if the user's icon size isn't set to 32x32 (like it's set to 48x48 for example) the Delphi7 TImageList fails with an "Invalid image size" error.

Does anyone know if a workaround is available? I've tried using TPngImageList but it leads to other issues.

Also, please note that I'd like to preserve the Alpha channel of the icons. Normal 1-bit transparency is not enough, as icons tend to look ugly that way.

Thanks!

3

There are 3 answers

2
Steve On BEST ANSWER

Just when I was about to give up this page led me to the solution: http://delphihaven.wordpress.com/2010/09/06/custom-drawing-on-glass-2/

Apparently, if you try to add an icon that is bigger than 32x32 to a timagelist in Delphi7, the VCL will give you an "Invalid image size" error while it could simply call the himagelist API - which can easily handle it.

Here is the complete solution:

unit ImageListFix;

interface

uses CommCtrl, Graphics, ImgList;

type
  TImageListFixer = class(TCustomImageList)
  public
    function AddIcon(Image: TIcon): Integer;
  end;

implementation

function TImageListFixer.AddIcon(Image: TIcon): Integer;
begin
  if Image = nil then
    Result := Add(nil, nil)
  else
  begin
    Result := ImageList_AddIcon(Handle, Image.Handle);
    Change;
  end;
end;

end.

And the code for adding icons to the system imagelist:

DocumentImgList:=TImageListFixer(GetSystemLargeIconsList);

IconToAdd:=TIcon.Create;
try
  IconToAdd.Handle := LoadImage(0, 'c:\Ico1.ico', IMAGE_ICON, DocumentImgList.Width, DocumentImgList.Height, LR_LOADFROMFILE);
  DocumentImgList.AddIcon(IconToAdd);

  IconToAdd.Handle := LoadImage(0, 'c:\Ico2.ico', IMAGE_ICON, DocumentImgList.Width, DocumentImgList.Height, LR_LOADFROMFILE);
  DocumentImgList.AddIcon(IconToAdd);
finally
  IconToAdd.Free;
end;
1
David Heffernan On

I'm not aware of any limitation on the size of images that TImageList can hold. It sounds to me that your problem is that you have icons of different sizes and you can't hold icons of different sizes in the same image list.

If you are working with icons of different sizes then you are going to need to grow the smaller ones in size. You'll have to build it up in code, using a bitmap. You fill the bitmap with pure transparent alpha channel and then blt the smaller icon onto the centre of the bitmap.

Another option would be to maintain two separate image lists but if you need to draw the icons into the same list view then I think that won't get the job done. My guess is that you'll need to grow the small icons.

For alpha, you're going to need to create the image list handle yourself because the ColorDepth property doesn't exist in D7. Because of this, a vanilla D7 TImageList simply cannot support icons with alpha channels.

You work around this limitation by calling ImageList_Create, passing ILC_COLOR32 and assigning the result to ImageList.Handle. Do this before you add any images. You'll have to populate the list at run time rather than design time, but it sounds like you are already doing that.

Here's a screen shot of a 48x48 tool button with a 32bpp icon with alpha transparency:

48px icon from image list

It's true that I made this in D2010, but my above workaround will work for D7 – I used that mechanism until quite recently with D6. I'm just showing this to prove that the image list can hold 48px icons. Since TImageList is just a wrapper around the system image list component, I believe what you are attempting should be perfectly feasible.

0
Remy Lebeau On

TImageList raises an "Invalid image size" error under only 2 conditions:

1) The TImageList's Height or Width property is less than 1, or the Height property is greater than 32768, when the TImageList is initially created via the CreateSize() constructor (there are no such limitations imposed by the Height and Width property setters).

2) you try to add/insert a new TBitmap or TIcon whose dimensions do not fit within TImageList's internal image.