Download the source code of this example
(Source: http://www.vckbase.com/document/viewdoc? Id = 492
)
Since windows
Since its launch, the system tray application, as an attractive UI, has been favored by many users. There are countless Windows applications using the system tray UI, such as Kingsoft
Ba "," Winamp ", and" RealPlayer. So how to write your own tray application? This is the first article in the series. These articles will systematically describe the application of pallets.
Programming. And create your own C ++ class to enhance the features of the system tray application. After reading these articles, let's look at the examples. I believe that readers can easily apply system pallets in their own programs.
As we all know, the MFC framework does not provide any ready-made classes for the system tray UI. How can I add the icon indicating the application to the taskbar? The method is very simple. Only one API function is used.
Is shell_policyicon. This function is quite easy to understand and use. Look at its prototype and you will know:
BOOL Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA pnid
);
The first parameter dwmessage is of the DWORD type, indicating the action to be performed. It can be one of the following values:
Nim_add: add an icon to the taskbar.
Nim_modify: Modify the icon in the status bar area.
Nim_delete: Delete the icon in the status bar area.
Nim_setfocus: return the focus to the taskbar notification area. This message is required for the taskbar icon when you complete operations on the user interface. For example, if the taskbar icon is positive
The context menu is displayed, but you press the "escape" key to cancel the operation. You must use this message to return the focus to the taskbar notification area.
Nim_setversion: indicates that the taskbar works according to the corresponding dynamic library version.
The second parameter pnid is the address of the policyicondata structure, and its content depends on the value of dwmessage. This structure is defined in the shellapi. h file as follows:
Typedef struct _ policyicondata {
DWORD cbsize; // structure size (sizeof struct), which must be set
Hwnd; // window handle for sending notification messages
Uint uid; // icon ID (specified by wparam of the callback function)
Uint uflags;
Uint ucallbackmessage; // the process in which the message is sent to this window
Hicon; // icon handle
Char sztip [64]; // prompt text
} Policyicondata;
Uflags value:
# Define nif_message 0x1 // indicates that ucallbackmessage is valid.
# Define nif_icon 0x2 // indicates that hicon is valid
# Define nif_tip 0x4 // indicates that the sztip is valid.
For details about how to use the shell_policyicon function, refer to msdn.
Hwnd in the notifyicondata structure is "owned"
The window handle of the icon. UID can be the ID of any Tray Icon (if there are multiple icons), the resource ID is generally used. Hicon can be the handle of any icon, including predefined system icons, such
Idi_hand, idi_question, idi_exclamation, or Windows logo idi_winlogo.
It is not difficult to display the icon. The key is to process the event.
When you move the mouse over the icon or click the mouse over the icon, you can assign your message ID to ucallbackmessage for notification and set
The nif_message flag. When you move or click the icon, Windows uses the window handle specified by hwnd to call the window creation process. The message ID is
Ucallbackmessage specifies that the UID value is wparam, and lparam is a mouse event, such as wm_lbuttondown.
Although the shell_policyicon function is simple and practical. However, it is a Win32
API, So I encapsulated it in a C ++ class. This class is called ctrayicon. With this class, Tray programming is easier and easier, because it hides
Yyicondata, message code, logos, and all the complicated details that you have to watch msdn to complete. For the definition and implementation details of ctrayicon, download the source code parameters.
Exam. Ctrayicon provides a more friendly tray programming interface for programmers. Besides packaging the shell_policyicon function, ctrayicon is also a mini framework!
This is because this class enhances the User Interface Behavior of the tray icon according to the principles advocated in the Windows System Application Software Interface Guide (this guide can be found in msdn. Below
This is the UI feature of ctrayicon:
1. The Tray Icon should have a prompt, that is, tooltips.
2. Right-click the context menu, which should contain the command to open the property page or other window commands related to the icon.
3. Click the left button to display further information or objects represented by the control icon. For example, you can control the volume when you click the sound icon with the left button. If there is no further information or control, do not take any action.
Ctrayicon fully encapsulates the above features. To demonstrate how ctrayicon works, this article provides an example program traytest1. Figure 1 shows a dialog box after running the program:
Figure 1 dialog box displayed after running traytest1
After installing the icon on the system tray, if you double-click the tray icon, the program will pop up a message List window, as long as your mouse moves or clicks on the tray icon (whether it is a left or right key click or double-click), the generated messages will be displayed in this window, 2:
Figure 2 message display window
When you move the cursor over the tray icon, a message is displayed near the icon:
Figure 3 tooltip
To correctly use the ctrayicon, you must first instantiate the ctrayicon somewhere in the program. The example program creates a ctrayicon instance in the main framework.
Class MainFrame public CFrameWnd {protected: CTrayIcon m_trayIcon; // my tray icon
…….
};
Then, you must provide an ID. This is the only icon in the life cycle of the icon, even if you modify the icon to be displayed in the future. This ID is also the id you will obtain when a mouse event occurs. It is not necessarily a graph.
Resource ID. In this example, the ID is idr_trayicon, and m_trayicon is initialized by the Framework constructor cmainframe through the member initialization list.
:
CMainFrame::CMainFrame() : m_trayIcon(IDR_TRAYICON){
……
}
To add an icon, you must call one of the following seticon functions as needed:
M_trayicon.seticon (idi_myicon); // resource ID
M_trayicon.seticon ("myicon"); // Resource Name
M_trayicon.seticon (hicon); // hicon
M_trayicon.setstandardicon (idi_winlogo); // System icon
Except seticon (uint
In addition to UID), these functions all have an optional parameter of the lpcstr type to specify the prompt text. Seticon (uint
UID) use the string resource with the same ID and UID as the prompt text. For example, traytest1 has a line of code like this:
// (In the mainframe. cpp file)
M_trayicon.seticon (idi_myicon );
This line of code also sets the prompt information, because traytest1 has a string of resources, and its ID is also idi_myicon. This is shown in the traytest. RC file:
Stringtable preload discardable
Begin
Idi_myicon "double-click the icon to activate traytest ."
End
If you want to change the icon, you can use a different ID or hicon to call one of the seticon functions again. Ctraytest uses nim_modify instead of nim_add to change the icon. The same function can even be used to delete icons, such:
M_trayicon.seticon (0); // Delete the icon
Ctrayicon interprets this code as nim_delete. As you can see, all the codes and symbols that indicate behavior are replaced by a convenient function: All thanks to C ++! Now
Now let's take a look at how to handle notification messages and all the UI features mentioned above. To process a notification message, you must set the icon, but call
Ctrayicon: setnotificationwnd. The best place to do this is in the oncreate processing routine, where traytest handles
Of:
// Register custom messages for pallets
# Define wm_my_tray_notification wm_user + 0
Int cmainframe: oncreate (maid)
{
......
// Notify me
M_trayicon.setnotificationwnd (this,
Wm_my_tray_notification );
M_trayicon.seticon (idi_myicon );
Return 0;
}
Once a message is registered, you can use the common message ing method to process the notification messages in the tray.
Begin_message_map (cmainframe, cframewnd)
On_message (wm_my_tray_notification,
Ontraynotification)
// (Or on_registered_message)
End_message_map ()
Lresult
Cmainframe: ontraynotification (wparam WP, lparam LP)
{
......
// Display the message
......
Return m_trayicon.ontraynotification (WP, LP );
}
When the message processor is controlled, the value of wparam is the ID specified when the ctrayicon is constructed, and lparam is a mouse event (such as wm_lbuttondown ). When you get
After the notification message is sent, you can do anything you want. The example program traytest displays the notification information. For details, see the source code. After processing the message, call
Ctrayicon: ontraynotification for default processing. This virtual function (so you can rewrite it) implements the default UI behavior I mentioned earlier. Especially Processing
Wm_lbuttondblclk and wm_rbuttonup. Ctrayicon: Find a menu with the same ID as the icon (for example, idr_trayicon ).
When you right-click the icon, The ctrayicon displays this menu. When the number of users double-click the icon, The ctrayicon executes the first menu command. There are only two things that need further explanation:
The first thing is: Before the menu is displayed, ctrayicon sets the first menu item as the default, so it is displayed in black. But how can I display a menu item in the black body? I am at/msdev
/Include/*. h: search for it and find get/setmenudefaultitem. This function has no related cmenu packaging class, so I must call it directly.
.
// Set the first menu item to default (in bold ):
: Setmenudefaultitem (psubmenu-> m_hmenu, 0, true );
Here 0 indicates the first menu item. True indicates that the position indicates the ID of the menu item. Why didn't MFC package the get/setmenudefaultitem function? Microsoft
This is because these functions (Other functions include: Get/setmenuiteminfo,
: LoadImage, etc.) has not been implemented in the latest Windows version. Once implemented in the latest Windows version, it will be immediately added to the MFC.
The second thing is the display of the context menu:
::SetForegroundWindow(m_nid.hWnd); ::TrackPopupMenu(pSubMenu->m_hMenu, ...);
To make trackpopupmenu run correctly in the context of the tray, you must first call setforegroundwindow. Otherwise, when you press the Escape key
Or when you click the mouse outside the menu, the menu does not disappear. I spent several hours solving this problem and finally found a solution on msdn. For more information, see
Q135788. What makes me laugh the most is that I spent so much time paying attention to this issue. Finally, the Microsoft guys came to you with a question on msdn: "This
Behavior is
Design... "is really a gas brake.
As you can see, ctrayicon makes the programming of the tray application easy. Traytest1 calls ctrayicon: ontraynotification to implement a notification message processor and provides a menu with the same ID as the icon. That's simple.
// (Traytest. RC file)
Idr_trayicon menu discardable
Begin
Popup "tray (& T )"
Begin
Menuitem "open (& O)", id_app_open
Menuitem "about traytest (& A)...", id_app_about
Menuitem Separator
Menuitem "Exit traytest Program (& S)", id_app_suspend
End
End
When you right-click the tray icon, ctrayicon displays this menu, as shown in figure 4. If you double-click the icon, ctrayicon executes the first menu command: "open ".
Live traytest (hidden under normal conditions ). To terminate traytest1, You must select "Suspend
Traytest "menu item. If you exit from "file | exit" or close the main traytest1 window, traytest1 will not actually close, but it just hides itself. This
Traytest1 overrides the cmainframe: onclose implementation.
Figure 4 traytest1 Tray Icon menu
Finally, I want to explain a very worrying issue. After seeing this small icon, everyone wants to add the tray icon to their programs as soon as possible. As a programmer, this is completely understandable. When your program
The tray icon was successfully added and showed off among friends. It was really good. But remember: not all applications need to use the tray icon. If not, do not draw a picture. Otherwise, the tray chart
Too many labels will inevitably cause screen garbage. See figure 5 below:
Figure 5 "nightmare version" of the tray icon Program"
Seeing so many tray icons is a nightmare for users. (To be continued)