How to draw standard Windows file information for pagecontrol tab index

I would like the icons of standard windows (and warnings and errors) to be drawn before the index of the pagecontrol tab. However, the result does not look good if the background color of Windows 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 think this is due to the lack of proper alpha transparency according to the TImageList, but I do not know how to fix it.

The solution is not required to use TImageList, I am glad to use any other approach. Note that there will also be headers, and not all indexes will have icons, and the icons can be changed / added / removed as the context changes.

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

+5
source share
2 answers

As @Sertac says, you see the effect of resizing the Windows shell icon from 32x32 to 16x16. As a workaround starting with Windows Vista, you can use SHGetStockIconInfo . passing the SHGSI_SMALLICON flag to get a small version of the icon, as indicated by SM_CXSMICON and SM_CYSMICON .

The values โ€‹โ€‹of SM_CXSMICON and SM_CYSMICON depend on the current DPI setting. For DPI 96 16x16 .

Example

  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; 
+6
source

What you see is not related to broken alpha transparency, but to the artifact of resizing.

As documented , the default size of the LoadImage icon LoadImage loaded by SM_CXICON x SM_CYICON , which is usually 32x32. Since you are requesting an icon that is used by the system, this will be the size of the icon to be specified.

You can check if this matches your code:

  .. try icon.Handle := LoadImage( 0, IDI_INFORMATION, IMAGE_ICON, 16, 16, {LR_DEFAULTSIZE or} LR_SHARED ); Assert(icon.Width = GetSystemMetrics(SM_CXICON)); Assert(GetSystemMetrics(SM_CXICON) <> 16); .. 

It follows that the icon changes to fit the list of images, probably nothing better than StretchBlt with COLORONCOLOR mode.

Unfortunately, it is not possible to load a system icon with a custom size, because, as documented again,

When loading a system icon or cursor, you must use LR_SHARED or the function cannot load the resource.


What you need to do is load the generic icon with its default size and then change it to 16x16 using the best algorithm. StretchBlt with HALFTONE will probably be better, but using a more advanced graphics library can give the best results.

A fail-safe alternative is to load the resource directly from where it is located. If you do not use the LR_SHARED flag, you will be provided with the required size. You need to do some research to find the actual icon index, as this is not documented. And keep in mind that the index or its life may change over time. Do not forget to destroy the icon yourself in this case, since the system will not do this for a non-shared resource.

 icon.Handle := LoadImage(GetModuleHandle(user32), Pointer(104), IMAGE_ICON, 16, 16, 0); 
+3
source

Source: https://habr.com/ru/post/1273693/


All Articles