I use a tool to observe two measured values from different thermometers via RS232. When I work with other applications on my computer during the observation time, I can't see the measured values in the dialog window, because the tool is overlaid with the window of the application. So I needed a display which is independent from the state of the desktop. I decided to write the values in icons and show these icons in the system tray repetitively.
After reading other articles about icons in the system tray, you might ask what is special in this demo? The main point of interest in this demo is the dynamic creation of the icons at runtime in a simple way and updating of the system tray permanently with these icons.
There are two versions of the code. The first time, I submitted the article with the MFC demo project and explained the code. Six months later, I updated the article with a C# version. Because the C# code is much easier to understand, I leave the explanation for the MFC code untouched and just added the C# demo project. In this new project, you will find nearly all the methods and variables as in the MFC code because the principle has not changed.
Using the Code
The tool works like this: When the program starts, a static (default) icon appears in the system tray. Just when you push the 'Start' button, there will be two icons which show the changing values. You can hide the dialog with the minimize button. The program will disappear from the task bar, and only the changing icons will be shown in the system tray. With a double click on the icons, the dialog will popup to the desktop (or will be hidden from the desktop if the dialog was visible).
In the demo project, I use a counter to simulate the dynamics of the measured values. It is realized by a timer. At each timer event
TIMER1, the values are changed, the icons are drawn and then pushed into the system tray:
How to Create Icons?
In this demo, I show how to load and display a static icon from the resource view of the IDE and how to draw an icon at runtime. I use a static icon for the default icon, which was added and designed in the resource view. I use only the 16x16 pixel image type. The 32x32 pixel image type could be deleted or you use the same icon for the
IDR_MAINFRAME icon. The resource name is
IDI_ICON1. This name is necessary for the
NOTIFYCONDATA structures which will push the icon into the system tray (see below). To load the default icon at runtime, I use the following code:
HINSTANCE hInst =
hIcon = (HICON)LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON1),
Creating Icons at Runtime
Because a GDI+ graphics object is used, I implemented GDI+. How to do it is written in the article, Starting with GDI+.
This happens in
At first we have to prepare the value which should be written into the icon. For the used command
DrawString(), we need a
widechar array. Either we write the value directly to the
int size = sizeof(strValue)/sizeof(wchar_t);
swprintf( strValue, size, L"%3d", m_nValue1 );
... or we write the value in a
char array and convert it to a
int size = sizeof(strValue)/sizeof(wchar_t);
sprintf_s(txt, sizeof(txt),"%3d", m_nValue1);
MultiByteToWideChar(CP_ACP, 0, txt, -1, strValue, size);
In the next step, we provide a
Font and some formatting stuff:
Pen whitePen(Color(255, 255, 255));
PointF origin(-1, 1);
Now let's start with painting:
Graphics *graph = Graphics::FromImage(&bitmap);
graph->DrawLine(&whitePen, 0, 15, 15, 15);
graph->DrawLine(&whitePen, 0, 0, 15, 0);
graph->DrawString(strValue , -1, &font, origin, &format, &whiteBrush);
And at last, we convert the bitmap into an icon and save it to our icon handle
m_hIcon1. This handle is a member of our class because we need it later in
PushIcon1() to push it into the system tray.
Push the Icon into the System Tray
First we need a
NOTIFYCONDATA structure filled with some data including the name
ICON_VALUE1, a user defined message
WM_TRAY for the double clicks on the icon and the handle
m_hIcon1 of the created icon.
tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = m_hWnd;
tnid.uID = ICON_VALUE1;
tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnid.uCallbackMessage = WM_TRAY;
tnid.hIcon = m_hIcon1;
Take care of the resource names. There are three different names. The static default icon has the name
IDI_ICON1 and the other two icons have the self defined names
ICON_VALUE2 (see DynIconDlg.h).
It is possible to use a tooltip. After every change of values, the string
m_strTooltip will be updated. In this demo, I use the same tooltip for both icons and use the string as a member variable.
lstrcpyn(tnid.szTip, m_strTooltip, sizeof(tnid.szTip));
Now we have to check if the icon appears for the first time. Then we have to use the
Shell_NotifyIcon with the
NIM_ADD parameter, otherwise we just want to update the icon with the
m_bFirstIcon1 = FALSE;
Now the icon is in the system tray and we clean up:
The same procedure is also followed for the second icon in
The other methods in the code are commented. So I made my explanations short. I know that the code is not written very efficiently. But I think this enforces the understanding of the used methods.
- 29th November, 2007 - Created the article
- 10th June, 2008 - Updated the article with C# code