Implementing popup menus in VB6 is not necessarily intuitive but it isn't hard either. There is no menu or popup menu item in VB6 that you can drag from the Toolbox onto a form—thankfully this deficit has been rectified in VB.NET. This article will demonstrate how to create menus using the Menu Editor in VB6 and how to use those menus as popups. Demonstrating the context aspect I will borrow from an October 2001 article and demonstrate how to display the popup menu when a user right-clicks over an icon in the System Tray.
Creating Menus with the Menu Editor
Menus are added to Windows applications using the Tool, Menu Editor (Ctrl+E shortcut) in VB6. The Menu Editor allows you to create menus by typing the Caption and Name of each menu item and initialize menu items by setting properties for each menu item in the Menu Editor dialog box (see figure 1).
Referring to figure one, the menu item that has the focus is the item selected in the list in the bottom half of the Menu Editor dialog. Menu items at the extreme left edge are top-level menu items and each level of indentation represents an additional level of nesting.
Figure 1: The Menu Editor is used to design menus in VB6.
From figure 1 we can see that a top-level menu named Popup is selected. The caption that will be displayed is the value in the Caption field, in the example this is "Popup". If we were to add an ampersand to the value of the Caption property immediately before the first P in popup—&Popup—then the first P in popup would be the hotkey for the Popup menu. When the menu is displayed it would appear as follows: Popup. Further if the hotkey P were used then pressing Alt+P when the application containing the popup menu were run would cause the Popup menu to be displayed.
Other properties for the Menu Editor are pretty intuitive. You can use the VB6 help if you are unfamiliar with other Menu Editor properties.
If we were to check the Visible property for the menu shown then the Popup menu would appear as shown in figure 2 (when displayed).
Figure 2: The Popup menu described in the Menu Editor in figure 1 shown in design mode dropped down.
Menus that will be used as popup menus should not be displayed in the main menu bar when the application is running. Hence those menus that you will be using as popups should be made invisible by unchecking the Visible property in the Menu Editor as shown in figure 1.
As a reminder, you write code for a menu item by clicking on menu items in design mode. Thus you will need to make the menu visible to create the click event handler for the menu, or you can create the click event handler in the code editor in the usual way.
Displaying Menus as Popups
To display a menu as a popup call the PopupMenu method for a Form or MDIForm. For example, to display our Popup menu you can write the following code:
(Recall from figure 1 that we named the Popup menu MenuPopup. Prefixing object names with the object type is a convention I use.)
When you call the PopupMenu method the top-level menu item is not displayed. Applied to our example, if you displayed the MenuPopup object then only the MenuVisible item would be displayed.
There are other optional arguments that you can pass to the PopupMenu method. You can pass a flags argument that describes the alignment of the popup menu and values that describe special responses to mouse-clicks. The X and Y arguments allow you to precisely position the popup menu, and the last argument allows you to specify a menu that will be displayed using a Bold font style. The general syntax for the PopupMenu method follows.
object.PopupMenu menuname, flags, x, y, boldcommand
Refer to the PopupMethod Menu help information in the Visual Basic Reference. The information for this article was taken from the April 2001 MSDN documentation.
Adding a Popup to a System Tray Icon
Listing 1 provides a slightly revised re-listing of the System Tray example from "Using the System Tray", October 2001. If you want information about the code in general read the referenced October 2001 article on www.codeguru.com in VB Tech Notes. For our purposes we will go over the revision of the System Tray Demo that employs a popup menu.
Listing 1: Demonstrates a System Tray example from "Using the System Tray", October 2001, that has been revised to employ a popup menu.
1: ' FormMain.frm - Add an icon to the system tray. 2: ' Copyright (c) 2002. All Rights Reserved. 3: ' By Paul Kimmel. email@example.com 4: 5: Option Explicit 6: 7: ' Type passed to Shell_NotifyIcon 8: Private Type NotifyIconData 9: Size As Long 10: Handle As Long 11: ID As Long 12: Flags As Long 13: CallBackMessage As Long 14: Icon As Long 15: Tip As String * 64 16: End Type 17: 18: ' Constants for managing System Tray tasks, found in shellapi.h 19: Private Const AddIcon = &H0 20: Private Const ModifyIcon = &H1 21: Private Const DeleteIcon = &H2 22: 23: Private Const WM_MOUSEMOVE = &H200 24: Private Const WM_LBUTTONDBLCLK = &H203 25: Private Const WM_LBUTTONDOWN = &H201 26: Private Const WM_LBUTTONUP = &H202 27: 28: Private Const WM_RBUTTONDBLCLK = &H206 29: Private Const WM_RBUTTONDOWN = &H204 30: Private Const WM_RBUTTONUP = &H205 31: 32: Private Const MessageFlag = &H1 33: Private Const IconFlag = &H2 34: Private Const TipFlag = &H4 35: 36: Private Declare Function Shell_NotifyIcon Lib "shell32" _ Alias "Shell_NotifyIconA" (ByVal Message As Long, _ Data As NotifyIconData) As Boolean 37: 38: Private Data As NotifyIconData 39: 40: 41: Private Sub Form_Load() 42: AddIconToTray 43: Visible = False 44: End Sub 45: 46: Private Sub Form_Terminate() 47: DeleteIconFromTray 48: End Sub 49: 50: Private Sub AddIconToTray() 51: 52: Data.Size = Len(Data) 53: Data.Handle = hWnd 54: Data.ID = vbNull 55: Data.Flags = IconFlag Or TipFlag Or MessageFlag 56: Data.CallBackMessage = WM_MOUSEMOVE 57: Data.Icon = Icon 58: Data.Tip = "System Tray Demo - codeguru.com" & vbNullChar 59: Call Shell_NotifyIcon(AddIcon, Data) 60: 61: End Sub 62: 63: Private Sub DeleteIconFromTray() 64: Call Shell_NotifyIcon(DeleteIcon, Data) 65: End Sub 66: 67: Private Function GetWindowState(ByVal Value As Boolean) As Integer 68: 69: ' Abs(False) = 0 = vbNormal, Abs(True) = 1 = vbMinimized 70: GetWindowState = Abs(Value) 71: 72: ' Or 73: 'If (Value = False) Then 74: ' GetWindowState = vbNormal 75: 'Else 76: ' GetWindowState = vbMinimized 77: 'End If 78: 79: 80: End Function 81: 82: Private Sub Form_MouseMove(Button As Integer, _ 83: Shift As Integer, X As Single, Y As Single) 84: 85: Dim Message As Long 86: Message = X / Screen.TwipsPerPixelX 87: 88: Select Case Message 89: Case WM_LBUTTONDBLCLK 90: ToggleState 91: Case WM_RBUTTONDOWN 92: Call Me.PopupMenu(MenuPopup, , , , MenuVisible) 93: End Select 94: 95: 96: End Sub 97: 98: Private Sub ToggleState() 99: Visible = Not Visible 100: WindowState = GetWindowState(Not Visible) 101: End Sub 102: 103: Private Sub MenuVisible_Click() 104: ToggleState 105: End Sub
The menu described by figure 1 was added to the FormMain.frm from the SystemTrayDemo.vbp project. Line 91 from listing 1 adds the right mouse button constant to the Select Case statement. When the right mouse button is down over the icon in the System Tray the PopupMenu method is called displaying the MenuPopup menu.
As a side note the code in ToggleState was refactored using Extract Method. The result is that the popup menu's click event handler can use the behavior to show or hide the form, and the left button double click can use this method too.
Visual Basic 6 uses the Menu Editor to create and describe menus. The Menu Editor dialog is used to describe your main menu as well as menus that will be used as popup, or context, menus.
If you are going to use a menu as a popup menu then set its Visible property to false. When you are ready to show the menu call the Form.PopupMenu or MDIForm.PopupMenu method. The end result is a feature rich application that shows menus more appropriately displayed in a limited context.
Finally I'd like to mention that this article demonstrates how several techniques can be layered into an application to create a better final product. In this article the Refactoring Extract Method was employed to reuse code that toggled the visible state of the form. Additionally we were able to combine the popup menu with the system tray example to create a context menu for the system tray icon, yielding a handsome fit and finish.
About the Author
Paul Kimmel is a freelance writer for Developer.com and CodeGuru.com. Look for cool Visual Basic .Net topics in his upcoming book Visual Basic .Net Unleashed.
Paul founded Software Conceptions, Inc. in 1990. Contact Paul Kimmel at firstname.lastname@example.org for help building VB.NET applications or migrating VB6 applications to .NET.