Tuesday, March 10, 2020

System Tray Delphi Application

System Tray Delphi Application Take a look at your Task Bar. See the area where the time is located? Are there any other icons there? The place is called the Windows System Tray. Would you like to place your Delphi applications icon there? Would you like that icon to be animated - or reflect the state of your application? This would be useful for programs that are left running for long periods of time with no user interaction (background tasks you typically keep running on your PC all day long). What you can do is to make your Delphi applications look as if they are minimizing to the Tray (instead of to the Task Bar, right to the Win Start button) by placing an icon in the tray and simultaneously making your form(s) invisible. Lets Tray It Fortunately, creating an application that runs in the system tray is pretty easy - only one (API) function, Shell_NotifyIcon, is needed to accomplish the task. The function is defined in the ShellAPI unit and requires two parameters. The first is a flag indicating whether the icon is being added, modified, or removed, and the second is a pointer to a TNotifyIconData structure holding the information about the icon. That includes the handle of the icon to show, the text to show as  a tool tip when the mouse is over the icon, the handle of the window that will receive the messages of the icon and the message type the icon will send to this window. First, in your main forms Private section put the line:TrayIconData: TNotifyIconData; type TMainForm class(TForm) procedure FormCreate(Sender: TObject); private TrayIconData: TNotifyIconData; { Private declarations }public{ Public declarations }end; Then, in your main forms OnCreate method, initialize the TrayIconData data structure and call the Shell_NotifyIcon function: with TrayIconData dobegin cbSize : SizeOf(TrayIconData); Wnd : Handle; uID : 0; uFlags : NIF_MESSAGE NIF_ICON NIF_TIP; uCallbackMessage : WM_ICONTRAY; hIcon : Application.Icon.Handle; StrPCopy(szTip, Application.Title); end; Shell_NotifyIcon(NIM_ADD, TrayIconData); The Wnd parameter of the TrayIconData structure points to the window that receives notification messages associated with an icon.   The hIcon points to the icon we want to add to the Tray - in this case, Applications main icon is used.The szTip holds the Tooltip text to display for the icon - in our case the title of the application. The szTip can hold up to 64 characters.The uFlags parameter is set to tell the icon to process application messages, use the applications icon and its tip. The uCallbackMessage points to the application-defined message identifier. The system uses the specified identifier for notification messages that it sends to the window identified by Wnd whenever a mouse event occurs in the bounding rectangle of the icon. This parameter is set to WM_ICONTRAY constant defined in the interface section of the forms unit and equals: WM_USER 1; You add the icon to the Tray by calling the Shell_NotifyIcon API function. The first parameter NIM_ADD adds an icon to the Tray area. The other two possible values, NIM_DELETE and NIM_MODIFY are used to delete or modify an icon in the Tray - well see how later in this article. The second parameter we send to the Shell_NotifyIcon is the initialized TrayIconData structure. Take One If you RUN your project now youll see an icon near the Clock in the Tray. Note three things.   1) First, nothing happens when you click (or do anything else with the mouse) on the icon placed in the Tray - we havent created a procedure (message handler), yet.2) Second, there is a button on the Task Bar (we obviously dont want it there).3) Third, when you close your application, the icon remains in the Tray. Take Two Lets solve this backward. To have the icon removed from the Tray when you exit the application, you have to call the Shell_NotifyIcon again, but with the NIM_DELETE as the first parameter. You do this in the OnDestroy event handler for the Main form. procedure TMainForm.FormDestroy(Sender: TObject);begin Shell_NotifyIcon(NIM_DELETE, TrayIconData);end; To hide the application (applications button) from the Task Bar well use a simple trick. In the Projects source code add the following line: Application.ShowMainForm : False; before the Application.CreateForm(TMainForm, MainForm); E.g let it look like: ...begin Application.Initialize; Application.ShowMainForm : False; Application.CreateForm(TMainForm, MainForm); Application.Run;end. And finally, to have our Tray icon respond to mouse events, we need to create a message handling procedure. First, we declare a message handling procedure in the public part of the form declaration: procedure TrayMessage(var Msg: TMessage); message WM_ICONTRAY; Second, the definition of this procedure looks like: procedure TMainForm.TrayMessage(var Msg: TMessage);begincase Msg.lParam of WM_LBUTTONDOWN: begin ShowMessage(Left button clicked - lets SHOW the Form!); MainForm.Show; end; WM_RBUTTONDOWN: begin ShowMessage(Right button clicked - lets HIDE the Form!); MainForm.Hide; end; end;end; This procedure is designed to handle only our message, the WM_ICONTRAY. It takes the LParam value from the message structure which can give us the state of the mouse upon the activation of the procedure. For the sake of simplicity well handle only left mouse down (WM_LBUTTONDOWN) and right mouse down (WM_RBUTTONDOWN). When the left mouse button is down on the icon we show the main form, when the right button is pressed we hide it. Of course, there are other mouse input messages you can handle in the procedure, like, button up, button double click etc. Thats it. Quick and easy. Next,  youll see how to animate the icon in the Tray and how to have that icon reflect the state of your application. Even more, youll see how to display a pop-up menu near the icon.