Inside Delphi 2006 (Wordware Delphi Developers Library)

The TImageListEx component is a TImageList descendant that can use the images from another image list to generate disabled images, which can be used on toolbars and other user interface elements.

There are several benefits of the TImageListEx component:

To create the TImageListEx component, you have to derive it from the standard TImageList component and then create the DisableImage function for disabling an image and the AcquireDisabled procedure that uses the DisableImage function to disable all images from another image list.

The DisableImage function is not really complex. It first determines the "transparent" color by extracting the bottom-right pixel of the source image. Then it uses the "transparent" pixel to determine which pixels should be converted to grayscale and which should be copied. All pixels that match the "transparent" pixel are directly copied to the destination bitmap and all other pixels are first converted to grayscale and then copied to the destination image. Finally, it returns the "transparent" pixel as Result because we have to pass this value to the AddMasked method of TImageList component when adding images to the image list.

The following listing shows the entire DisableImage function.

Listing 28-4: Disabling an image

type TImageListEx = class(TImageList) private { Private declarations } protected { Protected declarations } function DisableImage(Source, Dest: TBitmap): TColor; end; ... function TImageListEx.DisableImage(Source, Dest: TBitmap): TColor; type TMyPixel = record Blue: Byte; Green: Byte; Red: Byte; end; PMyPixelArray = ^TMyPixelArray; TMyPixelArray = array[0..32767] of TMyPixel; var pSrc: PMyPixelArray; pDest: PMyPixelArray; x: Integer; y: Integer; gray: Integer; { these will hold the transparent color } tr: Integer; tg: Integer; tb: Integer; begin { first, make sure both are pf24bit } Source.PixelFormat := pf24bit; Dest.PixelFormat := pf24bit; { pixel at [W-1,H-1] in the Source is treated as "transparent" } pSrc := Source.ScanLine[Pred(Source.Height)]; with pSrc[Pred(Source.Width)] do begin tr := Red; tg := Green; tb := Blue; end; for y := 0 to Pred(Source.Height) do begin pSrc := Source.ScanLine[y]; pDest := Dest.ScanLine[y]; for x := 0 to Pred(Source.Width) do begin { if px <> transparent then grayscale it } if (pSrc[x].Red <> tr) or (pSrc[x].Green <> tg) or (pSrc[x].Blue <> tb) then begin gray := (pSrc[x].Red * 3 + pSrc[x].Blue * 4 + pSrc[x].Green * 2) div 9; pDest[x].Red := gray; pDest[x].Green := gray; pDest[x].Blue := gray; end else begin { if transparent then copy it } pDest[x].Red := pSrc[x].Red; pDest[x].Green := pSrc[x].Green; pDest[x].Blue := pSrc[x].Blue; end; // if pSrc end; // for x end; // for y { return the color used as transparent; we need to pass this to the AddMasked method when adding images to the image list } Result := RGB(tr, tg, tb); end;

The AcquireDisabled procedure accepts a source TCustomImageList object as the sole parameter and simply loops through its images, converting them to grayscale using the DisableImage function we created above.

To access a particular bitmap in a TImageList, you have to call the GetBitmap method, which accepts the image's index and a TBitmap where the GetBitmap method will store the requested image:

function GetBitmap(Index: Integer; Image: TBitmap): Boolean;

Finally, after you've acquired the original glyph from the source list and converted it to grayscale using the DisableImage function, you have to call the TImageList's AddMasked method to add the new glyph to the list. When calling the AddMasked method, you have to pass the glyph's transparent color as the MaskColor parameter to have the TImageList component generate the glyph's mask, which is used to draw the glyph transparently.

The following listing shows the AcquireDisabled procedure.

Listing 28-5: The AcquireDisabled procedure

procedure TImageListEx.AcquireDisabled(AList: TCustomImageList); var cnt: Integer; newImage: TBitmap; tempSource: TBitmap; transparent: TColor; begin { use AList's image size } Width := AList.Width; Height := AList.Height; { make sure there are no old images in the list } Clear; tempSource := TBitmap.Create; try newImage := TBitmap.Create; try for cnt := 0 to Pred(AList.Count) do begin { erase the old images because the GetBitmap method doesn't } tempSource.Assign(nil); newImage.Assign(nil); { resize the new image } newImage.Width := Width; newImage.Height := Height; { get image from the source image list } AList.GetBitmap(cnt, tempSource); { generate the new image } transparent := DisableImage(tempSource, newImage); { add the new image to the list } AddMasked(newImage, transparent); end; finally newImage.Free; end; finally tempSource.Free; end; end;

Using the TImageListEx Component

To use the TImageListEx component in an application, you have to do three things:

For instance, you can use the Delphi Text Editor example that we created earlier to test this component. First, remove the original disabled TImageList component and drop a TImageListEx component on the Designer Surface. Then, assign the TImageListEx component to the DisabledImages property of the main toolbar and write the following line in the OnCreate event handler of the main form:

procedure TMainForm.FormCreate(Sender: TObject); begin ImageListEx1.AcquireDisabled(Normal); end;

The TImageListEx will correctly create all disabled glyphs, except for the Delete button. The original Delete glyph cannot be successfully converted because this glyph, unlike almost all other GlyFX glyphs, treats the bottom-right pixel as a part of the image instead of as the "transparent" pixel. The following figure shows the original (erroneous) glyph and the updated glyph that can be successfully converted to grayscale by the TImageListEx component.

Figure 28-6: The troublesome Delete glyph

The toolbar in the following figure shows what the disabled glyphs generated by the TImageListEx component look like.

Figure 28-7: The final version of the Delphi Text Editor that uses the TImageListEx component

Finally, Figure 28-8 shows the impact of the TImageListEx component on the size of the Delphi Text Editor's executable. Although the Delphi Text Editor only had 10 disabled glyphs, the TImageListEx component managed to reduce the size of the executable by 17,408 bytes (17 KB).

Figure 28-8: The difference in the size of the executable after using the TImageListEx component

Категории