Animating System Tray Icons

 

This article explains how to animate an icon in the Shell tray and assign dynamically changing tooltips for each icon phase. So the end result will be that your icon can now visually indicate what your application is currently doing along with corresponding tooltip descriptions. User notifications like left click and right click on the icon are also handled. The Windows NT  resource usage indicator on the Shell Tray is a wonderful example of animating icons on the Shell Tray. Let's animate now !.

Step 1: (Setting up the data for the animation)

The first step involves setting up well organized arrays that kind of keep track of the icons lined up for animation along with their tooltip description strings. Also define a user defined notification that will let you know if the user clicked on the animating icon. Swing by at your resource editor and create all the icons that you need and give them the same ids specified in the array.

#define NUM_ICONS_IN_ANIMATION 5

static int iconResourceArray[NUM_ICONS_IN_ANIMATION] =
{ IDI_ICON1, IDI_ICON2, IDI_ICON3, IDI_ICON4, IDI_ICON5 };


static CString strToolTipArray[NUM_ICONS_IN_ANIMATION] = 
{ 
 CString("Resource Usage = 20%") ,
 CString("Resource Usage = 40%") ,
 CString("Resource Usage = 60%") ,
 CString("Resource Usage = 80%"),
 CString("Resource Usage = 100%") }; 


#define MYMSG_NOTIFYICON (WM_USER + 100)

Step 2:(Adding an useful helper function)

Take a look at this useful helper function below that wraps up the Shell_NotifyIcon call. The first  parameter indicates to the helper whether you need to add,delete, or modify an icon in the Shell Tray by specifying NIM_ADD, NIM_DELETE, or NIM_MODIFY. The second parameter indicates the index of the icon in the array that you set up in Step 1. The third parameter indicates the tooltip string for the currently displayed icon.

void CShellAnimDlg::InstallAnimatedIcon(DWORD dwMsgType,UINT nIndexOfIcon, CString strToolTip)
{

	//Load the specified icon from the array
	HICON hIconAtIndex = AfxGetApp()->LoadIcon(iconResourceArray[nIndexOfIcon]);

	
	///Fill up the NOTIFYICONDATA Structure
	NOTIFYICONDATA iconData;
	iconData.cbSize		= sizeof(NOTIFYICONDATA);
	iconData.hWnd		= GetSafeHwnd();  //window's handle
	iconData.uID			= 100 ;  //identifier
	iconData.uFlags		= NIF_MESSAGE|NIF_ICON|NIF_TIP; //flags
	iconData.uCallbackMessage	= MYMSG_NOTIFYICON; //notification handler
	iconData.hIcon		= hIconAtIndex;    //icon handle   
	
	//Fill up tool tip
	LPCTSTR lpszToolTip = strToolTip.GetBuffer(strToolTip.GetLength());
	lstrcpyn(iconData.szTip,lpszToolTip,strlen(lpszToolTip)+1);
												
	//Tell the shell what we intend doing
	//Add,Delete,Modify ---> NIM_ADD,NIM_DELETE, NIM_MODIFY in dwMsgType
	Shell_NotifyIcon(dwMsgType, &iconData); 


	//Resources are precious !
	if (hIconAtIndex)
		DestroyIcon(hIconAtIndex);
}

 

Step 3: (Animating the icon)

Whenever you need to start the animation, begin by adding an icon first on the tray by calling the helper function with NIM_ADD. Subsequently, cycle through the animation by calling NIM_MODIFY. The following code which is a dialog based application adds the first icon in OnInitDialog() and then sets up a timer that cycles through the animation.

BOOL CShellAnimDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    ///usual initialization goes here   	
    int nIndexFirstIcon = 0;
    InstallAnimatedIcon(NIM_ADD,nIndexFirstIcon,strToolTipArray[nIndexFirstIcon]);
    SetTimer(1,1000,NULL);
	    
    return TRUE; // return TRUE unless you set the focus to a control
}
void CShellAnimDlg::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	static int nCounter = 0;
	InstallAnimatedIcon(NIM_MODIFY,nCounter,strToolTipArray[nCounter]);
	m_nCounter = nCounter; //Store it here to keep track of the last displayed icon
	nCounter++;
	nCounter = nCounter%(NUM_ICONS_IN_ANIMATION);

	CDialog::OnTimer(nIDEvent);
}

Please Note: You may need to get the last icon off the tray when the application closes. So make sure you get the icon off the tray when your application closes by calling:

KillTimer(1);
InstallAnimatedIcon(NIM_DELETE,m_nCounter,"");

 

Step 4: (Handling notifications)

We now  need to keep track of  user actions on our icon.. Remember the user defined message id MYMSG_NOTIFYICON that we passed for callback notification to the NOTIFYICONDATA structure in the helper function. Well, the icon posts a message whenever the user performs an action on the icon. We are interested only on mouse clicks and so let's handle them. Firstly, go ahead and define a user defined message as shown in step 1. Once you're done with that , map the message handler to a function as shown below.

afx_msg void OnHandleIconNotify(UINT wParam, LONG lParam);                //function to handle notifications

ON_MESSAGE(MYMSG_NOTIFYICON,OnHandleIconNotify)      //message mapped to function

void CShellAnimDlg::OnHandleIconNotify(UINT wParam, LONG lParam)
{
    CString strTest;
    CString strCurrPosition(strToolTipArray[m_nCounter]);
    switch (lParam)
        {
        case WM_LBUTTONDOWN:
            break;
        case WM_RBUTTONDOWN:
            break;
        case WM_LBUTTONDBLCLK:
            ///Do whatever you need to do when the click occured
            //Current icon animation position is at m_nCounter
            
        default:
            break;
        }
    
}

 

You now have your animated icon cycling through it's phases on the Shell Tray with different tool tips depending on the icon position in the cycle order.

Last updated: 17 June 1998



Comments

  • Using AVI file

    Posted by Legacy on 05/17/2002 12:00am

    Originally posted by: Naresh

    Should include animation using AVI FILE.

    Reply
  • This is what I needed

    Posted by Legacy on 02/03/2001 12:00am

    Originally posted by: Mark Benchley

    This stuff is really nice!.
    I needed something like this for my application

    Reply
  • A Usefull Artical

    Posted by Legacy on 09/22/1999 12:00am

    Originally posted by: Philip Heald

    Thanks I found this artical extreamly usefull, it described exactly how to do something I've been trying to do for a few days !!!!

    Reply
  • Other implementations

    Posted by Legacy on 04/05/1999 12:00am

    Originally posted by: Scott Seely

    For another implementation of a similar concept, you can go to ftp://ftp.mfi.com/pub/windev/1998/nov98.zip. I wrote an article for the November 98 issue of WDJ that covers the same topic, although with a slightly different angle. All the animation jive is hidden from the user. Anyhow, if you want another implementation, download the above file. The archive within NOV98.ZIP that you want is SEELY.ZIP.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Savvy enterprises are discovering that the cloud holds the power to transform IT processes and support business objectives. IT departments can use the cloud to redefine the continuum of development and operations—a process that is becoming known as DevOps. Download the Executive Brief DevOps: Why IT Operations Managers Should Care About the Cloud—prepared by Frost & Sullivan and sponsored by IBM—to learn how IBM SmartCloud Application services provide a robust platform that streamlines …

  • Live Event Date: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today make data protection a must-have, as we live in a data driven society. The digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join eVault Chief Technology …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds