delphiiconstpagecontrol

How to paint standard windows information icon nicely to the index of a pagecontrol's tab


I would like the standard windows information (and warning and error) icons painted to the index of a tab of a pagecontrol. However the result is looking bad if the windows background color is not white.

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.

Here is a screenshot: enter image description here

As you can see the white border is fuzzy, I guess it is because of lack of proper alpha transparency by TImageList but I don't know how to fix this.

The solution does not have to use TImageList, I am happy to use any other approach. Note that there will be also captions and not all indexes will have icons and the icons might changed/added/removed as the context changes.

I am using Delphi XE-2, I also have the DevExpress components if that helps.


Solution

  • As @Sertac says what you see is the effect of resize the windows shell icon from 32x32 to 16x16, As workaround starting with Windows Vista you can use the SHGetStockIconInfo function. passing the SHGSI_SMALLICON flag to retrieve the small version of the icon, as specified by the SM_CXSMICON and SM_CYSMICON.

    The values of SM_CXSMICON and SM_CYSMICON depends of the current DPI Setting. For DPI 96 is 16x16.

    Sample

      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;