Как красиво нарисовать значок информации о Windows в индекс вкладки управления страницы
Я хотел бы, чтобы стандартные значки информации о Windows (и предупреждения, и ошибки) отображались в указателе вкладки элемента управления страницы. Однако результат выглядит плохо, если цвет фона окна не белый.
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.
Как вы можете видеть, белая рамка размыта, я думаю, это из-за отсутствия надлежащей альфа-прозрачности в TImageList, но я не знаю, как это исправить.
Решение не должно использовать TImageList, я счастлив использовать любой другой подход. Обратите внимание, что будут также заголовки, и не все индексы будут иметь значки, и значки могут изменяться / добавляться / удаляться при изменении контекста.
Я использую Delphi XE-2, у меня также есть компоненты DevExpress, если это помогает.
2 ответа
Как говорит @Sertac, вы видите эффект изменения размера оболочки Windows с 32x32 до 16x16. В качестве обходного пути, начиная с Windows Vista, вы можете использовать SHGetStockIconInfo
функция. прохождение SHGSI_SMALLICON
флаг, чтобы получить уменьшенную версию значка, как указано SM_CXSMICON
а также SM_CYSMICON
,
Значения SM_CXSMICON
а также SM_CYSMICON
зависит от текущей настройки DPI. Для DPI 96 это 16x16.
Образец
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;
То, что вы видите, не из-за нарушенной альфа-прозрачности, а из-за изменения размеров.
Как указано в документации, размер значка по умолчанию LoadImage
нагрузки это SM_CXICON
ИксSM_CYICON
, что, как правило, 32x32. Так как вы запрашиваете значок, который является общим для системы, это будет размер значка, который будет предоставлен.
Вы можете проверить, так ли это в вашем коде:
..
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);
..
Из этого следует, что размер иконки изменяется в соответствии со списком изображений, вероятно, ничем не лучше, чем StretchBlt
с COLORONCOLOR
Режим.
К сожалению, невозможно загрузить системный значок с нестандартным размером, потому что, как снова задокументировано,
При загрузке системного значка или курсора вы должны использовать LR_SHARED, иначе функция не сможет загрузить ресурс.
Вам нужно загрузить общий значок с его размером по умолчанию, а затем изменить его размер до 16x16, используя лучший алгоритм. StretchBlt
с HALFTONE
было бы, вероятно, лучше, но использование более продвинутой графической библиотеки могло бы дать лучшие результаты.
Настоятельно не рекомендуется загружать ресурс непосредственно из того места, где он находится. Если вы не используете LR_SHARED
флаг вам будет дан запрошенный размер. Вам нужно провести некоторое исследование, чтобы найти фактический индекс значка, поскольку это не задокументировано. И нужно учитывать, что индекс или где он живет, может измениться во времени. В этом случае не забудьте уничтожить значок самостоятельно, поскольку система не сделает этого для ресурса, не являющегося общим.
icon.Handle := LoadImage(GetModuleHandle(user32), Pointer(104), IMAGE_ICON, 16, 16, 0);