Difference between revisions of "Talk:How to use a TrayIcon"

From Free Pascal wiki
Jump to navigationJump to search
(New page: Could someone expand on this comment "The image of the icon can be altered using a HICON handle. "? As a newbie I don't really know what a HICON handle is or how to use it. I have found i...)
 
Line 7: Line 7:
 
  SysTrayIcon.Show;
 
  SysTrayIcon.Show;
  
I found that the format of the icon in Windows XP is very fussy.
+
I found that the format of the icon in Windows XP is fussy.
The icon will only display if it contains a 32x32 image saved with the parameters "8bpp,1-bit alpha,256-slot palette" in gimp for example.
+
The icon will only display if it is saved with the parameters "8bpp,1-bit alpha,256-slot palette" in gimp for example.
  
 
The next challenge is to modify an icon in memory and then display it.
 
The next challenge is to modify an icon in memory and then display it.
Line 15: Line 15:
 
Also any attempt to do a SysTrayIcon.Icon.LoadFromBitMapHandles() seems to result in a blank icon.
 
Also any attempt to do a SysTrayIcon.Icon.LoadFromBitMapHandles() seems to result in a blank icon.
  
In the end I did this which works
+
In the end I did this which works for a 32x32 icon
  
 
  MemIcon:=TIcon.Create;
 
  MemIcon:=TIcon.Create;
Line 47: Line 47:
 
I have no idea what the first 100 bytes do.
 
I have no idea what the first 100 bytes do.
  
The last annoyance is that other icons in my system tray appear to be 16x16 yet I can't get SysTrayIcon to display a 16x16 icon (maybe I haven't tried hard enough).  Windows seams to scale my 32x32 icons down to fit which means a softer icon with missing pixels :-(
+
For a 16x16 icon there is no extra 100 bytes and the colour order is different.
Still, at least it works and I can programmatically modify them
+
Same code for a 16x16 icon
 +
 
 +
procedure TForm1.SetIconPixel(PTRIcon:PIcon;xpos,ypos,red,green,blue:byte);
 +
var
 +
  PByte: ^Byte;
 +
begin
 +
  {xpos and ypos are 0 to 15}
 +
  PByte:=PtrIcon^.RawImage.Data+((xpos+(ypos*16))*3);
 +
  if PByte<PtrIcon^.RawImage.Data+PtrIcon^.RawImage.DataSize-1 then
 +
  begin
 +
    Pbyte^:=blue;
 +
    (PByte+1)^:=green;
 +
    (PByte+2)^:=red;
 +
  end;
 +
  end;
 +
 
 +
To use this procedure you have to  
 +
load an icon file or resource into a ticon
 +
send a pointer to the ticon and the xpos, ypos and colour that you want to the procedure
 +
copy the icon to the systrayicon
 +
show it
 +
 
 +
like this
 +
MemIcon:=TIcon.Create;
 +
MemIcon.LoadFromFile('16x16.ico');
 +
//draw a black square in the middle
 +
for x:=6 to 9 do
 +
  for y:=6 to 9 do
 +
    SetIconPixel(@MemIcon,x,y,0,0,0);
 +
SystrayIcon.Icon:=MemIcon;
 +
SystrayIcon.Show;
 +
 
 
[[User:Dieselnutjob|dieselnutjob]]
 
[[User:Dieselnutjob|dieselnutjob]]

Revision as of 00:16, 25 July 2010

Could someone expand on this comment "The image of the icon can be altered using a HICON handle. "? As a newbie I don't really know what a HICON handle is or how to use it.

I have found it quite hard to generate icons that will load and display using

SysTrayIcon.LoadFromFile('file.ico');
SysTrayIcon.Show;

I found that the format of the icon in Windows XP is fussy. The icon will only display if it is saved with the parameters "8bpp,1-bit alpha,256-slot palette" in gimp for example.

The next challenge is to modify an icon in memory and then display it. I'm sure my method isn't exactly correct but maybe it will help others. First I tried to create a tbitmap and load an icon into it but fails. Also any attempt to do a SysTrayIcon.Icon.LoadFromBitMapHandles() seems to result in a blank icon.

In the end I did this which works for a 32x32 icon

MemIcon:=TIcon.Create;
MemIcon.LoadFromLazarusResource('blankicon');
PByte:=MemIcon.RawImage.Data+100;
//PByte now points to the first byte of the first pixel.
//Set the top left pixel red
Pbyte^:=$00; //green
(PByte+1)^:=$FF;  //red
(PByte+2)^:=$00:  //blue
SysTrayIcon.Icon:=MemIcon;
SysTrayIcon.Show:

Now I have an icon in my system tray with a red dot in the top left corner. Each pixel uses 3 bytes so a procedure like this works to manipulate each 32x32 pixel

procedure TForm1.SetIconPixel(PTRIcon:PIcon;xpos,ypos,red,green,blue:byte);
var
  PByte: ^Byte;
begin
  {xpos and ypos are 0 to 31}
  PByte:=PtrIcon^.RawImage.Data+100+((xpos+(ypos*32))*3);
  if PByte<PtrIcon^.RawImage.Data+PtrIcon^.RawImage.DataSize-1 then
  begin
    Pbyte^:=green;
    (PByte+1)^:=red;
    (PByte+2)^:=blue;
  end;
end;

I have no idea what the first 100 bytes do.

For a 16x16 icon there is no extra 100 bytes and the colour order is different. Same code for a 16x16 icon

procedure TForm1.SetIconPixel(PTRIcon:PIcon;xpos,ypos,red,green,blue:byte);
var
  PByte: ^Byte;
begin
  {xpos and ypos are 0 to 15}
  PByte:=PtrIcon^.RawImage.Data+((xpos+(ypos*16))*3);
  if PByte<PtrIcon^.RawImage.Data+PtrIcon^.RawImage.DataSize-1 then
  begin
    Pbyte^:=blue;
    (PByte+1)^:=green;
    (PByte+2)^:=red;
  end;
end;

To use this procedure you have to load an icon file or resource into a ticon send a pointer to the ticon and the xpos, ypos and colour that you want to the procedure copy the icon to the systrayicon show it

like this

MemIcon:=TIcon.Create;
MemIcon.LoadFromFile('16x16.ico');
//draw a black square in the middle
for x:=6 to 9 do
  for y:=6 to 9 do
    SetIconPixel(@MemIcon,x,y,0,0,0);
SystrayIcon.Icon:=MemIcon;
SystrayIcon.Show;

dieselnutjob