10 January 1999: New Version 2 - a major upgrade to the control. Read about the changes to the
Download the cPopMenu control (50kb)
Download the cPopMenu sample application code (82kb)
Download the complete cPopMenu demonstration and control source code (169kb)
Source Code Note
This OCX is a binary compatible component which works with all other samples.
If you compile your own copy of this OCX yourself please make sure you change
the name. See disclaimer and license for more details.
Before you Begin
These projects require the SSubTmr.DLL component. Make sure you have loaded and registered this before trying any project.
The cPopMenu control is a really simple way to get icons into a VB project's menus. It also allows you
to create arbitrary new submenus, gives you control over the system menu and has some useful new events
indicating when menu items are highlighted and exited.
Introducing the PopMenu Control
VB is a great language and interface designer, don't get me wrong. But sometimes you get the feeling
there just hasn't been enough effort put in. Two particular examples are the printer object (better than
it used to be, but still not very good!) and menus.
When you first start VB5, you are presented with a wonderful interface: all the menus have icons which
reflect the toolbar function, and there are neat popup right-click menus everywhere. So I naturally
thought we'd get these functions to use ourselves for our own VB applications. Er... no.
Instead we get the same old menu control that's been there since whenever. You've got to predesign
your menus at design time, and although you can add new levels to a existing menu, you're stuck if
you want to add a new submenu.
I found that for my application I needed to create a Favorites menu. The Internet Explorer Favourites list
seemed to be a good model as it allows you to organise stuff it you want to, or just add it straight in.
Since you can't add a submenu to an existing menu in VB, however, you just can't do it! (Or, at least, you
could but you would have to harshly restrict where things can be organised to).
Rather than give up (which maybe I should have, because for various reasons, which were unusally not code related, that application never got
completed!) I decided to build a menu control which allows you to create arbitrary numbers of sub-menus
at run time. At the same time I added icon support so you get Office/VB style menus for VB.
How PopMenu Works
The cPopMenu control is a VB UserControl which is invisible at runtime. When you call the initialisation
method (SubClass) the control uses the Win32 API menu functions to determine what menus there are on the
form and stores their IDs, captions, enabled state and so on in an internal array.
At the same time it also converts them to Owner-Draw menu items, so the cPopMenu
control is notified when the menu items need drawing, and can draw the menu as required.
Finally, the control subclasses the form so it can react to menu items being higlighted, clicked and when a
popup menu is just about to be drawn.
This means that the control draws over the existing VB menus, but still allows the old menu events to be
fired in code. By exposing properties to access the internal array, the control allows icons to be
associated with the existing menu items, as well as allowing you store some useful extra information
against the menu items (Key, HelpText, ItemData etc).
Quick Start - Adding Icon Menu Support to an Existing Application
Adding Icon Menu support to an existing application can be very simple, depending on what VB menu features
you use. If you don't use the menu Load,Unload,Caption or Visible methods, you only have to
add a small amount of code. I'll cover this case now.
The steps are:
- Add a cPopMenu to your form. If you don't already have an ImageList, add one with the icons you want.
You can use either a standard COMCTL32.OCX image list or a vbAccelerator
Image List control/class as the Image List.
- Initialise the cPopMenu control and the icons against the menu items in the Form_Load event as follows:
And that's it! Everything else will continue to work as before. If you use the Caption property,
there is a minor change you must make to make sure the menu item keeps being owner-drawn. Instead
' Associate the image list:
' NOTE: If you are using a VB ImageList, make sure that it has at
' least one icon in it before calling this method.
.ImageList = ilsIcons
' Parse through the VB designed menu and sub class the items:
' The Key property for a VB menu is set to the menu's name.
' In this example I set the icon for the mnuFileOpen menu item:
.ItemIcon("mnuFileOpen") = ilsIcons.ListImages("OPEN").Index-1
' Repeat for your other menus
mnuFile(0).Caption = "&Open Project..."
cPopMenu1.Caption("mnuFile(0)") = "&Open Project..."
If you use VB's Load, Unload methods or the Visible property, however,
you'll need to modify the code a bit more to use the new Add and Remove menu features.
Adding, Inserting and Deleting Menu items
You can extend existing menus, create as many new sub-menus as you want and modify items in
the menu using the following methods:
Menu items added or inserted using these methods do not raise events through the standard VB menu events.
(This is because your menu might be a completely new sub-menu, which has no corresponding VB event to fire through!)
Instead the ItemClick event of cPopMenu fires, passing the index of the menu in the control. You should use
cPopMenu's ItemData, MenuKey and Caption properties to make it easier to identify which
item has actually been clicked.
This adds a new item to the menu. You can specify a parent item if you want to create a new submenu.
- InsertItem New! 10 January 1999
This works in the same way as add item, but allows you to insert an item to the menu. In combination
with the RemoveItem method this makes it much easier to work with menu items.
- RemoveItem New! 10 January 1999
Removes an item from a menu.
- ReplaceItem New ! 10 Janury 1999
Similar to AddItem, but instead replaces an existing menu item. This allows you to change
multiple properties of the menu item at the same time.
This clears all the menu items in a submenu. You can then use the AddItem and InsertItem methods
to rebuild the list.
Menu items deleted using ReplaceItem or ClearSubMenusOfItem are hard-deleted from the control.
If you ever subsequently want to get these items back again, you need to re-add them.
cPopMenu and the VB Menu .Visible Property
Unfortunately, VB implements menus with .Visible set to false by actually deleting the
menu handle entirely from the menu. Because the cPopMenu control must use Windows API methods
to work with the menu, it cannot detect VB menus which are not visible. Here is an overview
of what happens with menus that have .Visible = False:
There is now a work-around in the control for the lack of the .Visible property support in the control,
but it still can't really address the problems. To use this method, whenever you change a menu item's
.Visible property, you can call cPopMenu's CheckForNewMenuItems event. This rechecks all
the menu items and:
- Menus set to be Invisible in the VB Menu designer
In this case the menu is not created when you the run the VB project. When you call
cPopMenu's SubClassMenu method, it will have
no reference to these menu items. The worst case is when all menu items are set to be invisible
in the designer - then the cPopMenu will find no menus at all and will return a completely blank
menu and the .MenuCount property will return 0! If you are trying to do this, it is likely
you are trying to create a pop-up menu with the submenu of one or more of the invisible items.
In this case you should use the Pop-up Menu ActiveX DLL instead - it is
much better suited to the task!
- Setting .Visible = False at run-time.
In this case, the cPopMenu control will have a reference to the menu until you set .Visible = False.
When you do this, VB deletes the menu handle that cPopMenu is refering to. The control still thinks
the menu is valid even though it has been removed. You can continue to set properties for the removed
menu item but they will have no effect. When you set .Visible True again, VB creates a completely
new menu handle for the item which the control does not know about - it still looks for the old menu
handle. The new menu will not be owner-drawn and you will not be able to refer to it from the control.
It is recommended that you avoid using the .Visible property and instead rewrite your code to
use cPopMenu's AddItem, InsertItem and RemoveItem properties instead. These
properties are much more flexible and allow you to add unlimited menu items at any level in the
- Removes items which have been made invisible in VB
- For each menu item which was previously invisible but has subsequently been made visible, it fires
a RequestNewMenuItem event. You must fill in the Icon, Tag, Itemdata and other properties each
time, because the cPopMenu control cannot keep track of menu items which are added and removed.
Recoding for Load and Unload Methods
The VB Load and Unload methods for menu items will interfere with the operation of the
cPopMenu control in a similar way to the .Visible property:
Again, you can work around these issues by using the CheckForNewMenuItems method, but it is
recommended you recode using the AddItem, InsertItem and RemoveItem properties
- Load will successfully add a new menu, but the menu will not be under cPopMenu's
control and you will not be able to set icons for it.
- Unload will remove the menu from the display
but the cPopMenu control will still think that exists.
About the Demonstration Project
The demonstration project shows how to exercise all these features, including dynamically building a
menu from a directory listing (it checks for subdirectories below the project itself).
Further projects demonstrating more advanced techniques with the control are also available:
Documentation for the cPopMenu control is available in RTF format. This documentation was
created with the Active X Documenter, which is also available
Click here to download/view the cPopMenu method and event documentation
Back to top
Back to Source Code