Example with ComboBox
To use TImageList, drop an TImageList object onto the form. In this example we need six images.
All images must be the same size. If two sizes of image are to be used, then two TImageLists must be used.
Set the height and width of the images in the Object Inspector; In this case 50px wide by 18px high.
Set Style to csOwnerDrawFixed.
Double-click on the TImageList icon to open the TImageList editor. Make sure that the icons show correctly when selected. If they are smaller than expected, check the size in the Object Inspector <F11>. You may have to reload the images.
Place a ComboBox on the form and name it cbSymbols.
In the FormCreate event enter:
cbSymbols.Items.Clear; for I := 0 to 5 do cbSymbols.Items.Add(''); cbSymbols.ItemIndex := 0;
This will write 6 blank entries, and select the first.
In the OnDrawItem event for cbSymbols place the following code:
procedure TMyForm.cbSymbolsDrawItem( aControl: TWinControl; iIndex: Integer; aRect: TRect; aState: TOwnerDrawState ); var cnv: TCanvas; begin if not (aControl is TComboBox) then exit; cnv := TComboBox( aControl ).Canvas; Imagelist1.Draw( cnv, aRect.Left+2, aRect.Top+2, iIndex ); end;
The adjustments (+2) are to center the image in the item, if necessary.
Example with SpeedButton
Add images to the ImageList1 like in the previous example and use:
Multiple-resolution TImageList in Lazarus 1.9 and newer
In Lazarus 1.9 the TImageList was rewritten to support multiple resolutions of one image.
Every LCL control that supports ImageList has now a new [Images]Width property to decide what custom width at 96 PPI (100% scale) is to be used. Example: TToolBar.Images/ImageWidth, TListView.LargeImages/LargeImagesWidth.
Set the Scaled property to True and the image list will automatically pick up the scaled image in your High-DPI aware LCL application.
There are 2 demo applications in Lazarus sources:
Changes affecting backwards compatibility
- Old behavior: the image got sliced if too big or extended if too small.
- New behavior: the image is scaled to all resolutions in the image list.
- Reason: Image List now supports multiple resolutions.
- Remedy: use AddSliced (if the image consists of several icons to be added) or AddSlice (if one image from a custom rect has to be added - also rect outside the image is supported).
How to create multi-resolution ImageList in the application
- In the first step you must tell the Imagelist which image sizes are needed.
- Decide on the basic image size, usually 16x16. This is used at 96ppi screen resolution (in Windows: 100%).
- If your application will also run at 144ppi (150%) or 192ppi (200%), it will also need images at 24x24 and 32x32 (24 = 150% of 16, 32 = 200% of 16).
- Click on the New resolutions button and specify each of these extra sizes (only the width must be entered). The 16x16 size does not need to be added by the New resolutions button because it is already known from the Imagelist.Width and .Height properties.
- In the case that some controls require a larger image size at 96pp, say 32x32, you should also prepare the imagelist for these scaled sizes, i.e. size 48 (=150% of 32) and 64 (=200% of 32) in this example.
- In the next step you add the images themselves.
- Click on the Add more resolutions button.
- Navigate to the folder in which your images are stored (The png image format is highly recommended). Lazarus 2.3+, for example, has the images/general_purpose folder in its installation directory which is full of free png images designed for typical applications (thanks to Roland Hahn...). (svg master files can be found at https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/image_sources/lazarus/images/general_purpose/).
- Multi-select all sizes of the image that you want to load.
- OK loads the images into the image list editor; missing sizes will be scaled down from larger sizes in surprisingly good quality.
- Repeat with the other motives that you need.
- Add only images that you need - they require a fairly large amount of memory.
- If you draw the images yourself, you may skip all the intermediate sizes. The minimum is to draw the largest images that you need; the smaller ones are scaled down automatically upon loading. However, the smallest image (16x16), sometimes also 24x24, appears a bit fuzzy; therefore, it is recommended to provide special versions of these sizes as well. It is maybe a good idea to draw the images in vector format (svg, using Inkscape) and to export to the needed size in png format.
- Finally select the controls which require the non-standard default size and set their ImagesWidth to the corresponding value. In case of a TListView having a SmallImages and a LargeImages property, for example, set the LargeImagesWidth to 32; the SmallImagesWidth can stay at its default value, 0, because it is interpreted as the default size defined by the Imagelist.Width.
High-DPI alternative for Lazarus 1.8 and older: resize all images in TImageList
This is useful for example for High DPI scaling to get icons with higher resolution for TActionList, TMainMenu and TToolBar. Note: This may not work correctly with all widgetsets on all platforms. Note also: This code is not required for Laz 1.9+.
procedure ScaleImageList(ImgList: TImageList; NewWidth, NewHeight: Integer); var TempImgList: TImageList; TempBmp1: TBitmap; TempBmp2: TBitmap; I: Integer; begin TempImgList := TImageList.Create(nil); TempBmp1 := TBitmap.Create; TempBmp1.PixelFormat := pf32bit; TempBmp2 := TBitmap.Create; TempBmp2.PixelFormat := pf32bit; TempBmp2.SetSize(NewWidth, NewHeight); try TempImgList.Width := NewWidth; TempImgList.Height := NewHeight; for I := 0 to ImgList.Count - 1 do begin // Load image for given index to temporary bitmap ImgList.GetBitmap(I, TempBmp1); // Clear transparent image background TempBmp2.Canvas.Brush.Style := bsSolid; TempBmp2.Canvas.Brush.Color := TempBmp2.TransparentColor; TempBmp2.Canvas.FillRect(0, 0, TempBmp2.Width, TempBmp2.Height); // Stretch image to new size TempBmp2.Canvas.StretchDraw(Rect(0, 0, TempBmp2.Width, TempBmp2.Height), TempBmp1); TempImgList.Add(TempBmp2, nil); end; ImgList.Assign(TempImgList); finally TempImgList.Free; TempBmp1.Free; TempBmp2.Free; end; end;