This is a conglomeration of ideas from the MSJ "Webster" application,
sniffing round the online docs, and from other implementations such
as PJ Naughter's "CTrayNotifyIcon" (
http://indigo.ie/~pjn/ntray.html) especially the "CSystemTray::OnTrayNotification"
member function and the SetStandardIcon stuff.
This class is a light wrapper around the windows system tray stuff. It
adds an icon to the system tray with the specified ToolTip text and
callback notification value, which is sent back to the Parent window.
The Old way:
The basic steps to using a tray icon via the windows API are:
Changing the values of the fields in NOTIFYICONDATA and calling
Shell_NotifyIcon allows you to change to icon or tool tip text or remove
the icon itelf. All this messing around has been bundled in a class wrapper
to make it easier and neater.
The Better way
The simpler way to add an icon to the system tray is to create an
object of type CSystemTray either as a member variable or dynamically.
Two forms of the constructor allow the programmer to insert the icon
into the tray as the CSystemTray object is created, or by using the
member function CSystemTray::Create. eg.
CSystemTray m_TrayIcon; // Member variable of some class
...
// in some member function maybe...
m_TrayIcon.Create(pParentWnd, WM_MY_NOTIFY, "Click here",
hIcon, nTrayIconID);
This will insert an icon in the system tray. See the following section for details.
Note that the destructor automatically removes the icon from the tray.
pWnd
Window where notification messages will be sent. May be NULL
uCallbackMessage
The notification messages that will be sent to the parent window
szToolTip
Tooltip for the tray icon
icon
Handle to the icon to be displayed
uID
Tray icon ID
If the pWnd parameter is NULL then the function CSystemTray::OnTrayNotification
will be called whenever the icon sends a notification message. See
Default message handling for more details.
LRESULT OnTrayNotification(WPARAM wID,
LPARAM lEvent) // Discussed below
void MoveToRight() // Moves the icon to the far right of the tray,
// so it is immediately to the left of the clock
void RemoveIcon() // Removes the icon from the tray (icon can no
// longer be manipulated)
void HideIcon() // Hides but does not totally remove the icon
// from the tray.
void ShowIcon() // Redisplays a previously hidden icon
BOOL SetTooltipText(LPCTSTR pszTip) // Set Tooltip text
BOOL SetTooltipText(UINT nID) // Set tooltip from text resource ID
CString GetTooltipText() const // Retrieve tool tip text
BOOL SetNotificationWnd(CWnd* pWnd) // Self explanatory
CWnd* GetNotificationWnd() const
HICON GetIcon() const // Get current tray icon
BOOL SetIcon(HICON hIcon) // Change tray icon. Returns FALSE if unsuccessful
BOOL SetIcon(LPCTSTR lpszIconName) // Same, using name of the icon resource
BOOL SetIcon(UINT nIDResource) // Same, using icon resource ID
BOOL SetStandardIcon(LPCTSTR lpIconName) // Load icon from the current application.
BOOL SetStandardIcon(UINT nIDResource)
BOOL SetIconList(UINT uFirstIconID, UINT uLastIconID); // Set list of icons for animation
BOOL SetIconList(HICON* pHIconList, UINT nNumIcons);
BOOL Animate(UINT nDelayMilliSeconds, int nNumSeconds = -1); // Start animation
BOOL StepAnimation(); // Step to next icon
BOOL StopAnimation(); // Stop animation
BOOL SetMenuDefaultItem(UINT uItem, BOOL bByPos); // Set default menu item
void GetMenuDefaultItem(UINT& uItem, BOOL& bByPos); // Get default menu item
SetStandardIcon can also take any of the following values:
nIDResource Description
IDI_APPLICATION Default application icon.
IDI_ASTERISK Asterisk (used in informative messages).
IDI_EXCLAMATION Exclamation point (used in warning messages).
IDI_HAND Hand-shaped icon (used in serious warning messages).
IDI_QUESTION Question mark (used in prompting messages).
IDI_WINLOGO Windows logo
The default CSystemTray message notification handler searches and displays
the menu with the same ID as the tray icon. If you use this default handler
then you can set the default menu item using SetMenuDefaultItem. The parameters
uItem and bByPos are the same as those used in ::SetMenuDefaultItem.
The default menu item code was contributed by Enrico Lelina.
Icon animation
Icon animation can be achieved by specifying a list of icons using SetIconList(...),
with either a range of icon resource IDs, or an array of HICONS and the size of the array.
Use "Animate(UINT nDelayMilliSeconds, int nNumSeconds)" to start the animation. The first parameter
is the delay in milliseconds between displaying each icon in the list, and the second is the
number of seconds for which to animate the icons. If -1 is specified then animation
will continue until StopAnimation() is called.
The parent window, on receiving a notification message, can redirect this
message back to the tray icon for handling by calling
CSystemTray::OnTrayNotification(...). Alternatively, if
the CSystemTray object was created with a NULL parent, then this function
will be called whenever the icon sends a notification. The default implementation
tries to find a menu with the same resource ID as the tray icon. If it finds a
menu and the event received was a right mouse button up, then the submenu is
displayed as a context menu. If a double click was received, then the message
ID of default item in the submenu (set using SetMenuDefaultItem) is sent back
to the parent window. If SetMenuDefaultItem has not been called then the default
menu item will be the first item in the menu
if (!m_TrayIcon.Create(this, WM_ICON_NOTIFY, strToolTip, hIcon, IDR_POPUP_MENU))
return -1;
where IDR_POPUP_MENU is the ID of a popup menu to display for the icon.
You then need a handler for the tray icon notification message:
LRESULT CMainFrame::OnTrayNotification(WPARAM wParam, LPARAM lParam)
{
// Delegate all the work back to the default implementation in CSystemTray.
return m_TrayIcon.OnTrayNotification(wParam, lParam);
}
The menu used (IDR_POPUP_MENU) looks like the following:
IDR_POPUP_MENU MENU PRELOAD DISCARDABLE
BEGIN
POPUP "POPUP_MENU"
BEGIN
MENUITEM "&About...", ID_APP_ABOUT
MENUITEM SEPARATOR
MENUITEM "&Options...", ID_APP_OPTIONS
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_APP_EXIT
END
END
A single right click on the tray icon will bring up this menu, while
a double click will send a ID_APP_ABOUT message back to the frame.
Alternatively, you can m_TrayIcon.Create(NULL, ...) and leave out
the message map entry for WM_ICON_NOTIFY. The default implementation
of CSystemTray will take care of the rest.
Many people have had troubles using TrackPopupMenu. They have reported that the popup
menu will often not disappear once the mouse is clicked outside of the menu, even though
they have set the last parameter of TrackPopupMenu() as NULL. This is a Microsoft
"feature", and is by design. The mind boggles, doesn't it?
Anyway - to workaround this "feature", one must set the current window as the
foreground window before calling TrackPopupMenu. This then causes a second
problem - namely that the next time the menu is displayed it displays then immediately
disappears. To fix this problem, you must make the currernt application
active after the menu disappears. This can be done by sending a benign message such
as WM_NULL to the current window.
Refer to KB article "PRB: Menus for Notification Icons Don't Work Correctly" for more info.
Last updated: 25 April 1998
Tools:
Add www.codeguru.com to your favorites Add www.codeguru.com to your browser search box IE 7 | Firefox 2.0 | Firefox 1.5.xReceive news via our XML/RSS feed
RATE THIS ARTICLE:
Excellent Very Good Average Below Average Poor
(You must be signed in to rank an article. Not a member? Click here to register)