Aquí hay (más o menos) una pregunta relacionada: Delphi - Populate an imagelist with icons at runtime 'destroys' transparency.Lista de imágenes con iconos de mezcla alfa pierde Transparencia
He probado @TOndrej answer. Pero parece que necesito tener estilos visuales (manifiesto de XP) habilitados para que esto funcione (se usará la versión 6.0 de los controles comunes de Windows, que no quiero en este momento). Agrego los iconos en tiempo de ejecución a través de ExtractIconEx
y ImageList_AddIcon
.
establecer parecer ImageList.Handle
utilizar mango Imagen-Lista de sistema, no requieren XP Manifiesto. así que incluso un programa anterior que escribí en D3 aparece con los iconos alfa mezclados correctamente cuando uso la lista de imágenes del sistema para mostrar la lista de archivos (con un TListView
).
Estaba vagando ¿Qué tiene de especial la Lista de imágenes del sistema y cómo se crea, por lo que es compatible con la mezcla alfa en todos los casos? No puedo entenderlo. Aquí hay un código de ejemplo:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, ImgList, StdCtrls, ShellAPI, ExtCtrls, Commctrl;
type
TForm1 = class(TForm)
ImageList1: TImageList;
PopupMenu1: TPopupMenu;
MenuItem1: TMenuItem;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
FileName: string;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// {$R WindowsXP.res}
procedure TForm1.FormCreate(Sender: TObject);
begin
PopupMenu1.Images := ImageList1;
FileName := 'C:\Program Files\Mozilla Firefox\firefox.exe';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
IconPath: string;
IconIndex: Integer;
hIconLarge, hIconSmall: HICON;
begin
IconPath := FileName;
IconIndex := 0; // index can be other than 0
ExtractIconEx(PChar(IconPath), IconIndex, hIconLarge, hIconSmall, 1);
Self.Refresh; // erase form
DrawIconEx(Canvas.Handle, 10, 10, hIconSmall, 0, 16, 16, 0,
DI_IMAGE or DI_MASK); // this will draw ok on the form
// ImageList1.DrawingStyle := dsTransparent;
ImageList1.Handle := ImageList_Create(ImageList1.Width, ImageList1.Height,
{ILC_COLORDDB} ILC_COLOR32 or ILC_MASK, 0, ImageList1.AllocBy);
ImageList_AddIcon(ImageList1.Handle, hIconSmall);
MenuItem1.ImageIndex := 0;
DestroyIcon(hIconSmall);
DestroyIcon(hIconLarge);
PopupMenu1.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
end;
procedure TForm1.Button2Click(Sender: TObject);
// using sys image-list will work with or without Manifest
type
DWORD_PTR = DWORD;
var
ShFileINfo :TShFileInfo;
SysImageList: DWORD_PTR;
FileName: string;
begin
SysImageList := ShGetFileInfo(nil, 0, ShFileInfo, SizeOf(ShFileInfo),
SHGFI_SYSICONINDEX OR SHGFI_SMALLICON);
if SysImageList = 0 then Exit;
ImageList1.Handle := SysImageList;
ImageList1.ShareImages := True;
if ShGetFileInfo(PChar(FileName), 0, ShFileInfo, SizeOf(ShFileInfo),
SHGFI_SYSICONINDEX OR SHGFI_ICON OR SHGFI_SMALLICON) <> 0 then
begin
MenuItem1.ImageIndex := ShFileInfo.IIcon;
Self.Refresh; // erase form
DrawIconEx(Canvas.Handle, 10, 10, ShFileInfo.hIcon, 0, 16, 16, 0,
DI_IMAGE or DI_MASK);
DestroyIcon(ShFileInfo.hIcon); // todo: do I need to destroy here?
PopupMenu1.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
end;
end;
end.
estilos visuales discapacitados:
estilos visuales Habilitado:
Una solución es utilizar la clase o subclase de interposición TImageList
y anular DoDraw
as shown here, pero lo que realmente quiero saber es cómo crear mi lista de imágenes igual que la lista de imágenes de sistema.
Nota: Conozco TPngImageList
y no quiero usarlo en este caso.
Editar: @ La respuesta de David (y comentarios) eran precisas:
que tendrá que vincular explícitamente a ImageList_Create (v6) porque de lo contrario, está implícitamente ligado al cargar el módulo tiempo y será unido a v5.8
código de la muestra (sin uso de API contexto de activación):
function ImageList_Create_V6(CX, CY: Integer; Flags: UINT; Initial, Grow: Integer): HIMAGELIST;
var
h: HMODULE;
_ImageList_Create: function(CX, CY: Integer; Flags: UINT;
Initial, Grow: Integer): HIMAGELIST; stdcall;
begin
// TODO: find comctl32.dll v6 path programmatically
h := LoadLibrary('C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll');
if h <> 0 then
try
_ImageList_Create := GetProcAddress(h, 'ImageList_Create');
if Assigned(_ImageList_Create) then
Result := _ImageList_Create(CX, CY, Flags, Initial, Grow);
finally
FreeLibrary(h);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
...
ImageList1.Handle := ImageList_Create_V6(ImageList1.Width, ImageList1.Height,
ILC_COLOR32 or ILC_MASK, 0, ImageList1.AllocBy);
...
end;
EDI2:A sample code by @David que muestra cómo se hace correctamente a través de la API de activación de contexto.
Eso tiene mucho sentido. Nunca pensé que la lista de imágenes del sistema puede usar un control de versión diferente fuera de mi proceso. en función de su respuesta [aquí] (http://stackoverflow.com/a/5133222/937125) Elimino la línea 'if IsLibrary then', pero no entiendo cómo hacerlo en mi EXE. especialmente las líneas: 'ActCtx.dwFlags: = ACTCTX_FLAG_RESOURCE_NAME_VALID o ACTCTX_FLAG_HMODULE_VALID;' y 'ActCtx.lpResourceName: = MakeIntResource (2);' – kobik
He intentado 'ActCtx.lpSource' con el manifiesto válido. 'ActCtx.dwFlags' se establece en 0. esa dosis no hizo ninguna diferencia. el ícono aún no es válido – kobik
Tendrá que vincular explícitamente a 'ImageList_Create' porque, de lo contrario, se vinculará implícitamente en el momento de carga del módulo y se vinculará a v5.8. No puedo decir que haya intentado esto alguna vez. No es un trabajo completamente trivial. Tendrá que mirar debajo de un depurador (por ejemplo, ms depends o process explorer) y asegúrese de estar haciendo v6 comctl para cargar. –