Now we will examine menu bars, menus, and menu items. Any window can have only one menu bar. Each menu bar is composed of one or more menus and menu items. These menu are placed horizontally accross the menu bar. Each menu in turn opens up into one or more menus and menu items.
This time we will create a basic notepad type window that can be found in MenuSample.cpp. Lets look at the main function.
00017: /////////////////////////////////////////////////////////////////////////////// 00018: ///Main function 00019: WPARAM main() 00020: { 00021: Window win( "Menu Bar Test" ); //Create the menu bar 00022: me = new MultilineEdit( 0, 0, 0, 0 ); //Create the edit window 00023: 00024: MenuBar mbar( &win ); //Create the menu bar 00025: createMenu( mbar ); //Add the menu items 00026: 00027: win.setMenuBar( &mbar ); //Set the menu bar 00028: win.add( me ); //Add the edit window 00029: 00030: win.show(); //Show the window 00031: 00032: //Set the edit window to the size of the window 00033: me->setSize( win.getWidth(), win.getHeight() ); 00034: 00035: //Start processing 00036: WPARAM param = win.beginMessageLoop(); 00037: 00038: //Delete the edit window 00039: delete me; 00040: 00041: return param; 00042: }
The window reference passed to the menu bar constructor is for the window that will recieve the events. This is handy because it allows you to add the same menu bar to more than one window. As you can see by line 27 you must tell the window what menu bar to display. When the window is created it will create the menu bar passed to setMenuBar(). The menu bar in turn will create the sub-menus, and the sub-menus will create the menu items. This means that menus bars that are unattached to a window at its create time must be created with a call to its create() method. The same holds true for menus and menu items that are unattached to either a menu bar, a popup menu, or another menu.
Lets look at the creteMenu() funcion to see how menu bars get their elements.
00044: /////////////////////////////////////////////////////////////////////////////// 00045: ///Create the menu for the menu bar 00046: void createMenu( MenuBar& mbar ) 00047: { 00048: Menu *menu = new Menu( "&File" ); //Create sub-menu called File 00049: 00050: MenuItem* mi = new MenuItem( "&New" ); //Create a menu item called New 00051: mi->addMenuCallBack( onNew ); //Set its callback 00052: menu->append( mi ); //Append to the sub-menu 00053: 00054: mi = new MenuItem( "&Save" ); //Create a menu item called Save 00055: mi->addMenuCallBack( onSave ); //Set its callback 00056: menu->append( mi ); //Append to the sub-menu 00057: 00058: mi = new MenuItem( "E&xit" ); //Create a menu item called Exit 00059: mi->addMenuCallBack( onExit ); //Set its callback 00060: menu->append( mi ); //Append it to the sub-menu 00061: 00062: mbar.append( menu ); //Append the sub-menu to the menu bar 00063: }
Menus and menu items take only one parameter in their constructor, a label that appears when the menu or menu item is shown. Currently only the append method can be used to add menus and menu items. You are probably wondering what those appersands are doing in the labels. Well if you press the ALT key, the focus jumps to the first item in the menubar. You will then see that the F of the File menu is underlined. If you then press F the File menu will open. Press X and the application will exit. You do not have to add the appersands but it is recomended to make your application accessible to the disabled, plus some times it is just convient to use the keyboard.
Next lets look at the menu item callbacks
00065: /////////////////////////////////////////////////////////////////////////////// 00066: ///Callback for "New" menu item 00067: BOOL onNew(MenuItem* item, UINT message) 00068: { 00069: //Set the edit window's text to \0 which 00070: //in effect empties the window 00071: me->setText( "" ); 00072: 00073: return TRUE; 00074: } 00075: 00076: /////////////////////////////////////////////////////////////////////////////// 00077: ///Callback for "Save" menu item 00078: BOOL onSave(MenuItem* item, UINT message) 00079: { 00080: static char text[256]; //Text buffer 00081: 00082: //Display the save file dialog 00083: char *fname = showSaveFileDlg( me->getParent() ); 00084: 00085: //If the user pressed OK 00086: if ( fname != NULL ) 00087: { 00088: me->getText( text, 256 ); //Get the edit window's text 00089: ofstream fout( fname ); //Open the file the user selected 00090: 00091: //Make sure it is open 00092: if ( fout.is_open() ) 00093: fout << text; //Output the edit window's text 00094: 00095: fout.close(); //Close the file 00096: delete[] fname; //Delete the file name 00097: } 00098: 00099: return TRUE; 00100: } 00101: 00102: /////////////////////////////////////////////////////////////////////////////// 00103: ///Callback for "Exit" menu item 00104: BOOL onExit(MenuItem* item, UINT message) 00105: { 00106: //Quit the application. 00107: Window::quitApp(); 00108: 00109: 00110: return TRUE; 00111: }
The important thing to notice about the callbacks is that they have different prototypes than the callbacks we use for components. The menu item have only two parameters. The first is a pointer to the menu item that generated the event. The second is the message generated. You will notice that I did not bother checking the message. That is because currently menu items can only process the WM_COMMAND event, this event is generated when the user clicks on the menu item. Note that menus do not currently generate events.