Home Articles Books Downloads FAQs Tips

Q: Create and remove menu items from code.


Background information:

Both TMainMenu and TPopupMenu contain an Items property. The Items property returns a TMenuItem pointer. The TMenuItem that is returned by the Items property represents an invisible root item that contains all of the menu items in the control. Think of this item as the root node of a tree view control. The only difference is that the root node of a tree view is visible.

TMenuItem has a Count property that returns the number children that are owned by the menu item. TMenuItem also contains an Items property. This property allows you to access all of the child menu items of the parent item. For example, imagine that your program has three main menu items called File, Edit and Help. The Items property of TMainMenu will return the invisible root item. The Count property of the root item will be three. The Items property of the root menu item will contain three child items: one for File, one for Edit, and one for Help. The following code explains this concept further.

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ListBox1->Items->Clear();

    TMenuItem *Root = MainMenu1->Items;

    Label1->Caption = IntToStr(Root->Count);
    for(int j=0; j<Root->Count; j++)
        ListBox1->Items->Add(Root->Items[j]->Caption);
}

This code isn't all that useful, but it does explain how the root menu item works. The code takes the top level menu items and inserts a string into a listbox for each one. If your program has top level menu items call File, Edit, and Help, then the code would put File, Edit, and Help into the listbox.

Most top level menu items contain other menu items as children. These child items can be accessed through the Items property of their parent. The following code places a string in a listbox for every menu item below the first top level menu item in the program.

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ListBox1->Items->Clear();

    TMenuItem *Root = MainMenu1->Items;
    if(Root->Count == 0)
        return;

    TMenuItem *FirstItem = Root->Items[0];
    for(int j=0; j<Root->Count; j++)
        ListBox1->Items->Add(FirstItem->Items[j]->Caption);
}

Of course, you don't have to retrieve the menu items from the Items property if your form class already contains TMenuItem pointers for all the menu items in your program.

TMenuItem contains a host of functions for adding and removing menu items. The Add method of TMenuItem adds a new child menu at the end of any existing menu items. The Add function takes a TMenuItem pointer as an argument. You must construct the menu item in code, assign its properties, and then call Add to make the item appear. Insert works just like the Add method, except that it takes an extra index argument that specifies where the new menu item should appear. You can delete a child menu item by calling the Delete method of its parent. Delete takes an integer index that determines which item should be nuked. You can also delete a child menu item by calling the Remove method. Remove takes a pointer to the menu item that should be deleted.

Note: Both the Remove function and the Delete function delete the TMenuItem pointer that they remove from the menu. You can no longer reference the menu item was you Remove or Delete it. For this reason, you probably should not Remove or Delete menu items that were created at design time, because those items have data members in the form class.

Adding new top-level menu items

This code adds a new top level menu item called Help, and several child menu items under the top level item.

void __fastcall TForm1::Button4Click(TObject *Sender)
{
    TMenuItem *Root = MainMenu->Items;

    // create a new menu item, set the owner to the form;
    TMenuItem *HelpItem = new TMenuItem(this);
    HelpItem->Caption = "&Help";
    Root->Add(HelpItem);

    // now add child items under the new Help item.
    TMenuItem *ContentsItem = new TMenuItem(this);
    TMenuItem *IndexItem    = new TMenuItem(this);
    TMenuItem *AboutItem    = new TMenuItem(this);
    ContentsItem ->Caption = "&Contents";
    IndexItem    ->Caption = "&Index";
    AboutItem    ->Caption = "&About";

    HelpItem->Add(ContentsItem);
    HelpItem->Add(IndexItem);
    HelpItem->Add(AboutItem);
}

Adding nested menus

This code adds new child items to an existing menu item. The code creates a menu that resembles the File | Reopen menu option in the C++Builder IDE.

void __fastcall TForm1::Button5Click(TObject *Sender)
{
    // existing menu item is a member variable called Reopen1
    // and four child menu items
    TMenuItem *Child1 = new TMenuItem(this);
    TMenuItem *Child2 = new TMenuItem(this);
    TMenuItem *Child3 = new TMenuItem(this);
    TMenuItem *Child4 = new TMenuItem(this);

    Child1->Caption = "c:\\cbuilder3\\projects\\project1.bpr";
    Child2->Caption = "c:\\cbuilder3\\projects\\project2.bpr";
    Child3->Caption = "-"; // separator bar
    Child4->Caption = "c:\\cbuilder3\\projects\\unit1.cpp";

    Child1->Default = true;

    Reopen1->Add(Child1);
    Reopen1->Add(Child2);
    Reopen1->Add(Child3);
    Reopen1->Add(Child4);
}

Removing a menu item

This code removes the last top level menu item. All children of this item are also destroyed.

void __fastcall TForm1::Button6Click(TObject *Sender)
{
    TMenuItem *Root = MainMenu1->Items;
    if(Root->Count > 0)
        Root->Delete(Root->Count -1);
}

Adding and Removing a menu item without deleting the object

As mentioned earlier, removing a menu item deletes the menu item pointer. This might be a problem if you want to add and remove the same menu item repeatedly. Instead of calling the Add and Remove methods, you can simply toggle the Visible property of a menu item. This keeps the menu item pointer intact. Here is a code example that hides or shows the Edit menu based on the state of a check box. Notice that hiding a parent item hides all of its child items.

void __fastcall TForm1::CheckBox1Click(TObject *Sender)
{
    EditMenuItem->Visible = CheckBox1->Checked;
}


Copyright © 1997-2000 by Harold Howe.
All rights reserved.