Why is my icon ugly on the tray bar with TTrayIcon?
Asked Answered
W

3

8

I recently discovered the TTrayIcon component in Delphi 2007. The code used is pretty straightforward.

procedure TForm1.FormCreate(Sender: TObject);
begin
 AppTrayIcon := TTrayIcon.Create(nil);
 AppTrayIcon.OnDblClick := OnAppTrayIconDblClick;
 Application.OnMinimize := OnApplicationMinimize;
 Application.OnRestore := OnApplicationRestore;
end;

procedure TForm1.OnApplicationRestore(Sender: TObject);
begin
 AppTrayIcon.Visible := False;
 ShowWindow(Application.Handle, SW_SHOW);
 Application.BringToFront;
end;

procedure TForm1.OnApplicationMinimize(Sender: TObject);
begin
 AppTrayIcon.Visible := True;
 ShowWindow(Application.Handle, SW_HIDE);
end;

procedure TForm1.OnAppTrayIconDblClick(Sender: TObject);
begin
 Application.Restore;
end;

Since there is no icon assigned, Delphi uses Application.Icon, which is that icon: http://artbyloveland.com/icon.ico This icon includes the following sizes: 64x64, 48x48, 32x32, 24x24 and 16x16.

Now, on my Windows Vista, everything fine.

On a non-themed Windows like Windows Server 2003, the result is all screwed-up:

Screwed-up icon

EDIT: At first, I thought it was because of the alpha channel. So I tried to make a version of the ico file without the use of alpha channel. I also tried GreenFish Icon Editor as suggested by Ken; I selected every color depth and every size available. In both cases, the end result is better. However, there is a black stroke that doesn't exist at all in the ico file.

Screwed-up icon 2

Whitley answered 28/11, 2012 at 13:43 Comment(7)
You need an HICON that is small icon size. Call GetSystemMetrics to find out how big that is. If, for example, the value is 20, then you don't have the right size. More probably, the component is using plain old LoadIcon and you've got a re-sampled 32px icon.Paff
Well, even if it was 20, it could be something else for another computer installation, right? At any case, I get 16 for SM_CXSMICON on my Windows 2003 server. I can fix the bug partly by applying Ken's advice; however, there is still a black stroke that doesn't exist in the first place in the ico file.Whitley
I always call Shell_NotifyIcon and pass in an HICON that I made with LoadImage. VCL handling of icons is hopeless. I don't see any evidence that you are doing anything other than letting this component use Application.Icon and that's doomed to failure.Paff
Using Shell_NotifyIcon and load the icon through LoadImage does the job! The end result is perfect. How do I accept your answer?Whitley
I'll write you an answer which you can then accept.Paff
In fact you can still use TTrayIcon I think. You just need to explicitly set the icon handle.Paff
what about learn.microsoft.com/en-us/windows/win32/api/commctrl/…Idio
P
8

You state that you are not assigning the icon. In which case the component uses Application.Icon. But that will typically be an icon that is the wrong size for the notification area.

For the notification area you need to use a square icon with size determined by the SM_CXSMICON system metric. The best way to get that is to call LoadImage which allows you to specify the icon size. Once you have loaded the icon into an HICON you can just write this:

AppTrayIcon.Icon.Handle := IconHandle;
Paff answered 28/11, 2012 at 20:29 Comment(1)
+1. Nice catch, David. It actually says that in the question (first sentence after the final code block), but I missed it (and apparently so did everyone else).Jinnyjinrikisha
J
6

You don't have the proper size or color depth for your icon.

You can use an icon editor to provide multiple size and color depth icons to a single .ico file, and Windows will automatically choose the proper one based on the user's settings and video driver configuration. Windows will then have several choices to use when selecting the closest match, and the scaling and blending will have a much better appearance.

I use GreenFish Icon Editor, which is donation-ware. It will allow you to open any supported graphic type and then create a Windows icon with multiple color depths and resolutions automatically from it (see the Icon menu). I've tested the multi-image icon files in Delphi 7, 2007, 2010, XE, and XE3, and they work fine for the Application.Icon and TForm.Icon.

Also see Best Icon size for displaying in the tray

Jinnyjinrikisha answered 28/11, 2012 at 13:51 Comment(8)
The question says there are already five icon sizes in the file. Which size is missing that's causing an inferior size to be selected for the notification area?Pyo
@Andreas: I copied it from the Help->About page from GFIE itself. I'll modify it to a download link instead (can't see where it ends up from where I am right now).Jinnyjinrikisha
@Rob: I didn't see the sizes when I posted my answer; all I saw was the link to the icon.ico file. The poster must have still been updating the original post as I posted mine (or I simply can't read before coffee <g>). There's also the issue of the color depth.Jinnyjinrikisha
Then a question to Allain instead: Which size or color depth did you add to the icon to solve your problem? If you didn't add anything, then you should not have accepted this answer yet.Pyo
Sorry, Rob, you're right; I've been too fast with everything. I'm updating my post. After, we can delete our comments to not clutter this question, I guess.Whitley
Would the downvoter care to explain? What is factually or technically wrong with my answer?Jinnyjinrikisha
ESet flags that greenfish editor as a virus. Suggest you remove the link.Agiotage
@AndyK: It's fine on my systems (AVG at home, Symantech at work). Did you submit the file to ESet to confirm it's not a false positive?Jinnyjinrikisha
S
1

I thought, I'd share my solution to this problem, as there is currently no complete solution here.

This problem was driving me nuts, because this is actually clearly a Delphi/VCL bug. If you assign an icon with all required sizes (16, 24, 32, 48, 256) to your project, Delphi should automatically use the correct size in TTrayIcon, but instead it only takes the 32px icon and scales it down.

Since the required images are already in the exe file (for being displayed in the Windows Explorer), you can simply fix it like this:

procedure FixTrayIcon(TrayIcon: TTrayIcon);
var
  i: Integer;
begin
  i := GetSystemMetrics(SM_CXSMICON); //Gets the correct size for the tray (e.g. 16)
  TrayIcon.Icon.Handle := LoadImage(hInstance, 'MAINICON', IMAGE_ICON, i, i, LR_DEFAULTCOLOR);
  TrayIcon.SetDefaultIcon; //Updates the icon
end;

Just call it in FormCreate and your tray icon will look as designed.

Shilohshim answered 9/7, 2019 at 17:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.