|
Delphi Tips and Tutorials
System tray icons tutorial
Part 2 - Changing the icon and responding to events
Delphi tips and tutorials -> System tray icons tutorial -> Part 1 -> Part 2 -> Part 3
Part 2 Introduction
This tutorial builds upon Part 1, so if you arrived here via
a search engine or similar, you may like to start at the beginning.
By the end of this tutorial, you will be able to:
- Change the icon displayed in the system tray,
- Show a popup menu when the icon is clicked.
Source code for this tutorial
This part of the tutorial builds upon the previous part, so if you didn't follow Part 1 of the tutorial, you will need to download the source code for Part 1 by clicking here.
If you don't want to enter the code for Part 2 yourself, you can download it here.
Tutorial begins here - 8 steps
STEP 1
First, we are going to create a popup menu which will appear when the user right clicks the icon. Add a
PopupMenu (located on the Standard tab in the Delphi IDE) to your form
(the form you created in Part 1) and change its
name to pmRightClick.
Add a single menu item to this popup menu, and call it "Change icon". Name this menu item miChangeIcon.
STEP 2
When the user clicks "Change icon", we want our code to change the icon to something different. Double-click the
"Change icon" menu item you just created, and enter the following code:
procedure TForm1.miChangeIconClick(Sender: TObject);
begin
ShowMessage('Change Icon clicked!');
end;
For now, we will just display the message "Change Icon clicked!". But by the end of this
tutorial we will modify this procedure to change the icon to something different.
STEP 3
For the purposes of this tutorial, we want the icon to show in the system tray as soon as the application is
started, without having to click the "Click Me!" button. We also want to remove the button so that
the user cannot remove the icon.
Double-click a blank area of the form to open the FormCreate procedure, and enter in the following code:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowTrayIcon;
Button1.Visible := False;
end;
This will cause ShowTrayIcon to be called as soon as the application starts, and hence
the tray icon will show immediately, and also remove the "Click Me!" button. (We will leave the actual button
on the form and just make it invisible, as we may need it again in the future.)
STEP 4
Do you remember the IconResponse procedure from Part 1? This is the function that is called when
the user clicks the tray icon. We can determine whether the left button or the right button was clicked by checking
if Msg.lParam is equal to either WM_LBUTTONDOWN or WM_RBUTTONDOWN,
which represent the left and right mouse buttons respectively.
In our case, if the user clicks the icon with the left button, we don't want anything to happen. But, if the
user clicks the icon with the right button, we want to display the popup menu we just created. The following code
will accomplish exactly this. Note that I have left WM_LBUTTONDOWN in the code as an example, even
though it does nothing.
Replace the empty IconResponse procedure from Part 1 with this new procedure:
procedure TForm1.IconResponse(var Msg: TMessage);
var
pt: TPoint;
begin
case Msg.lParam of
WM_LBUTTONDOWN:
begin
// Do nothing
end;
WM_RBUTTONDOWN:
begin
GetCursorPos(pt);
pmRightClick.Popup(pt.x, pt.y);
end;
end;
end;
Checkpoint
Try running the application. You should notice the icon appear automatically in the system tray.
First try clicking the icon with the left button - note that nothing happens. Then try clicking with the right button -
you should see the popup menu with one option "Change Icon". Click this item and ensure that the dialog box appears
as expected.
If the application does not compile, try working through the steps again, downloading the source code, or checking out
the Troubleshooting section at the bottom of the page.
Back to the tutorial...
STEP 5
See the three images to the right? There is a black sphere, a coral sphere, and a white sphere.
Each time we click the "Change icon" popup menu, we want the icon displayed in the system tray to
alternate between these three icons.
You will need to download each of the three icons. Download them here: (right click and select
"Save Target As...")
Black
Coral
White
Save them somewhere on your computer that is easily accessible. For the ease of finding them at a later date
you might like to place them under a new directory called "Images" under your Delphi Project directory.
STEP 6
You now need an image list to hold these icons. Add an ImageList control to your form (this control can be found
on the Win32 tab of the Delphi IDE) as shown in the picture.
Double click the image list, and add the three icons you downloaded in Step 5 to the list. You should end up with a
screen similar to the picture below.

STEP 7
It is now time to write the code to change the icon. There's quite a bit going on here.
First, we will declare a variable to keep track of which
icon is currently shown. Add the following variable to private declarations:
{ Private declarations }
FIconNumber: Integer;
...
Next, replace the miChangeIconClick with the following call:
procedure TForm1.miChangeIconClick(Sender: TObject);
begin
ChangeIcon;
end;
We will write the ChangeIcon procedure very soon. In the meantime, let's add
ChangeIcon to the end of FormCreate as well so that we don't get the ugly default Delphi icon appearing
on startup:
procedure TForm1.FormCreate(Sender: TObject);
begin
... existing code stays here ...
ChangeIcon; // Add this
end;
And write the ChangeIcon procedure as follows:
procedure TForm1.ChangeIcon;
var
LIcon: TIcon;
begin
Inc(FIconNumber);
if FIconNumber >= ilIcons.Count then
FIconNumber := 0;
LIcon := TIcon.Create;
try
ilIcons.GetIcon(FIconNumber, LIcon);
FTrayIconData.hIcon := LIcon.Handle;
Shell_NotifyIcon(NIM_MODIFY, @FTrayIconData);
finally
LIcon.Free;
end;
end;
The new ChangeIcon procedure does three things.
First, it increases FIconNumber to be the next number in
the sequence. If FIconNumber is now greater than the total number of icons in the imagelist, then it is reset
to 0.
Second, it loads the icon from the imagelist into a local TIcon.
Third, using NIM_MODIFY, it changes the existing icon in the system tray to the new icon.
STEP 8
One last optional step. If you run the application now, everything works (well... should work) as expected, except a blank form
appears on the screen. Let's add a friendly label to the form welcoming the user to our application (and let's move
the invisible button out of the way). You can see the end result in the image to the right.
Tutorial complete
Run the application, and instead of the ugly Delphi icon from Part 1, one
of the three icons that you downloaded earlier should appear, as shown here:

You should be able to right-click this icon and select "Change icon", and the icon will cycle through the different available icons.
If the project will not compile, see the Troubleshooting section at the bottom of the page.
Discussion
Technically, we don't need the main form at all. We really only need the icon in the
system tray. But then... how would the user close the application? The obvious way would be to add an "Exit" option to the popup menu. This is one of the things we will cover in Part 3.
Where to next?
Part 3 covers minimizing your application to the
system tray instead of the task bar, and also
starting the application with the main form invisible.
Troubleshooting
Are you having trouble getting your application to compile? Your problem might be covered
in the forum below. If not, you can ask there yourself.
Forum coming very very soon!
|