Ask the MultiValued Visual Basic Expert - #13A

(as published in Spectrum magazine Jan/Feb 1999)

To email your questions to "Ask the MultiValued VB Expert", click here.
Copyright 1996-98 Caduceus Consulting. All rights reserved.

Loading Custom Menus

I want to create a menu at run-time in a VB application. The Load statement can create one level of menu, but how can I create a multi-level menu (i.e. menu entries with sub-menus)? - Ajay Singh

Load Statement

A challenging question! Let me first back up a bit to bring the less intrepid readers up to speed. If you have spent much time with Visual Basic, you probably know that the Load statement is usually used to load forms (that you have created at design time) into memory, without showing them right away (the Show method performs a Load automatically, if required). You can then refer to controls on that form or call Public procedures on that form from other VB code, but the form will not become visible until you invoke CustBrowse.Show or set CustBrowse.Visible = True. Have a look at the following example:

Load CustBrowse
' Put in search criteria...
CustBrowse.txtSearch.Text = "Caduceus"
' Call Public function to search file...
NumFound% = CustBrowse.SearchDB("SUPPLIER")
If NumFound% > 1 Then
....' Make it visible and wait for a selection...
....CustBrowse.Show vbModal
End If
CustKey$ = CustBrowse.txtItemId.Text

After loading CustBrowse, two controls on the form (txtSearch and txtItemId) can be referred to from my current module, and I can call SearchDB, which is a Public function in the General section of CustBrowse. The browse form will only be shown if more than one entry is found.

Control Arrays

A more advanced use of the Load statement relates to creating new elements of a control array. A control array is simply an array of controls that are all of the same type. They all have the same Name property, and they are distinguished by an integral Index property (usually but not necessarily starting at 0). For example, I might have three phone number text boxes on a form that are referred to as txtPhone(0), txtPhone(1) and txtPhone(2). If you look at an event procedure for an element of a control array, you will notice that Visual Basic passes in an extra argument (Index) to each subroutine, so that you can tell which specific control the event was triggered for. You do not need to have more than one control in order to create a control array. By simply setting a control's Index property to any integer value, you have created a control array.

Loading New Controls at Run-Time

We can now put the preceding two concepts together. Imagine that I wish to create a fourth phone number text box on my form at run-time. The following code will do the trick:

Load txtPhone(3)
txtPhone(3).Top = 2100

Note that the new text box will have the same properties (including Top and Left values) as the first element, so I have to move it out from under txtPhone(0) to a visible position.

The Menu Problem

Ajay's problem is that he has created an array of menu controls in order to have a customizable menu at run-time. Unfortunately, menus and sub-menus have a nested parent-child relationship that is not controlled by properties. In other words, all menu controls that are loaded at run-time will be at the same level as the original element of the menu control array. Because all members of a single menu control array must be contiguous and at the same level (i.e. exist under the same parent menu entry), it is only possible to add new menu controls where originals already existed at design time. It is possible to overcome this obstacle, within limits that you impose when you first create the menu. Here's how:

Imagine that you want a menu called Clients, which lists several clients. Under each client, you want a sub-menu of cities where the clients have major offices. All of this information will be read from your MultiValue database at run-time. [I had to get the MultiValue database in there somewhere!] It is possible to do this, but only if you set a maximum number of clients that can appear. For simplicity, let us assume that the maximum is three. In the Menu editor at design time, create a tree of menu controls, named as follows, where the number in parentheses is the Index property:








Be sure to set the Visible property of all of the mnuClient and mnuCnCity controls to False. We can now use the following VB code (along with my handy MVB library) to create a customized menu at run-time:

For i% = 1 To NumClients%
....mnuClient(i%).Caption = mvbExtract(ClientListItem$, i%)
....mnuClient(i%).Visible = True
....CityList$ = mvbExtract(CityListItem$, i%)
....Select Case i%
....Case 1
........mnuC1City(1).Caption = mvbExtract(CityList$, 1, 1)
........mnuC1City(1).Visible = True
........For j% = 2 to mvbDCount(CityList$, VM)
............Load mnuC1City(j%)
............mnuC1City(j%).Caption = mvbExtract(CityList$, 1, j%)
............mnuC1City(j%).Visible = True
........Next j%
....Case 2
........mnuC2City(1).Caption = mvbExtract(CityList$, 1, 1)
........mnuC2City(1).Visible = True
........For j% = 2 to mvbDCount(CityList$, VM)
............Load mnuC2City(j%)
............mnuC2City(j%).Caption = mvbExtract(CityList$, 1, j%)
............mnuC2City(j%).Visible = True
........Next j%
....Case 3
........mnuC3City(1).Caption = mvbExtract(CityList$, 1, 1)
........mnuC3City(1).Visible = True
........For j% = 2 to mvbDCount(CityList$, VM)
............Load mnuC3City(j%)
............mnuC3City(j%).Caption = mvbExtract(CityList$, 1, j%)
............mnuC3City(j%).Visible = True
........Next j%
....End Select
Next i%

It's not the prettiest VB code ever written, but if you have to use menu controls (instead of something more flexible like combo boxes), the above solution is one way to make it work.

To email your questions to "Ask the MultiValued VB Expert", click here.
Copyright 1996-98 Caduceus Consulting. All rights reserved.
Revised: November 10, 1998.

Return to Caduceus Consulting Home Page

Copyright 2006 intellact
Last modified: Thursday May 25, 2006