Handling Events from Menus

I l @ ve RuBoard

Handling Events from Menus

There are several events that you can handle from a MenuItem . The most important is the one that you defined the item for in the first place. Remember from our button click example earlier that the events are hooked to the Click event source by a delegate defined by the system. In Listing 3.1.7, a handler that pops up a message box is defined and added to the methods of the SizeApp class.

Listing 3.1.7 A Simple Event Handler
 public class SizeApp : System.WinForms.Form {     public void OnFileOpen(Object sender, EventArgs e)     {         MessageBox.Show("You selected File-Open!");     } 

The event handler has the standard method signature for events void function ( Object , EventArgs) and can be added to the File, Open MenuItem 's Click event source like this:

 open.Click += new EventHandler(OnFileOpen); 

This line is added to the menu setup code after the shortcut initialization.

Whenever the menu item is selected with the mouse, the Alt+F+O key sequence, or the Ctrl+O shortcut, the menu handler will fire and the message box will pop up.

The complete C# file for the modified resize.cs program is available as resize2.cs on this book's Web site. You can find this at http://www.samspublishing.com/. Type in the ISBN 067232153X for this book.

User Interface Control Events for MenuItem s

Other events are fired by MenuItem s to enable you to give better feedback to the user or to customize the user experience. MFC had the CCmdUI class for this purpose. Windows Forms provides the Popup event source.

Just before a MenuItem is shown, the Popup event is fired to give you time to decide whether to show, check, or change the appearance of a menu item. You can trap this event by adding an event handler to the Popup event source:

 filemenu.Popup += new EventHandler(OnPopupFilemenu); 

The handler for this event is defined in Listing 3.1.8. It shows some of the standard things you can do, checking, enabling, hiding, and so on, with MenuItem s. The class has a Boolean variable called m_bPopupChecked . Every time the File menu is expanded, the program toggles this variable to true or false depending on its previous state. The Sender object is known to be a MenuItem , so it's possible to cast to that type safely. The three menu entries in the File menu are then checked, disabled, or hidden entirely, depending on the state of the variable. The image (seen in Figure 3.1.5) shows the menus in their two states.

Figure 3.1.5. The menu after the Popup event.

graphics/0301fig05.gif

Listing 3.1.8 The Popup Event Handler
 bool m_bPopupChecked; public void OnPopupFilemenu(Object Sender, EventArgs e) {     // this handler illustrates the Popup event and the MenuItem UI properties.     m_bPopupChecked = !m_bPopupChecked;     MenuItem item = (MenuItem)Sender;     item.MenuItems[0].Checked = m_bPopupChecked;     item.MenuItems[1].Enabled = m_bPopupChecked;     item.MenuItems[2].Visible = m_bPopupChecked; } 

Defining a MenuItem as a Separator

Very often a group of menu entries will be strongly associated with one another, or one menu item will be separated from another by strategic placement of a menu separator. Under Windows Forms the menu separator is a menu item that does nothing but draw a line across the menu. This is very simple; just set the text of a menu item to a single dash:

 MenuItem dummymenu = new MenuItem(); dummymenu.Text = "Separator"; menu.MenuItems.Add(dummymenu);     dummymenu.MenuItems.Add(new MenuItem("Above"));     dummymenu.MenuItems.Add(new MenuItem("-"));     dummymenu.MenuItems.Add(new MenuItem("Below")); 

Handling the Select Event

Once a menu item has been popped up, all of its visible members can be selected by positioning the mouse over them or using the arrows keys. When this selection takes place, an event is fired. The event source for this is called Select , and it is handled in much the same way as the Popup event.

The Select event is used primarily to update a status bar or other control with a help string that explains an otherwise cryptic menu entry. It could also be used for other user-interface customization.

The demonstration in Listing 3.1.9 uses the Select event to display a string in a label control on the client area.

Listing 3.1.9 menus.cs : Handling the Select Event
 using System; using System.Drawing; using System.ComponentModel; using System.WinForms; public class menuapp : System.WinForms.Form {     Label label;     void ShowInfo(Object Sender,EventArgs e)     {         MenuItem item=(MenuItem)Sender;         switch(item.Text)         {             case "&Open":                 label.Text = "Open a file from disk";             break;             case "&Save":                 label.Text = "Save a file onto disk";             break;             case "E&xit":                 label.Text = "Exit MenuApp";             break;         }     }     public  menuapp()     {         this.Text = "MenuApp";         this.MaximizeBox = true;         this.BorderStyle = FormBorderStyle.Sizable;         this.label = new Label();         label.Location = new Point(8,100);         label.Size = new Size(200,25);         this.Controls.Add(label);         MainMenu menu = new MainMenu();         MenuItem filemenu = new MenuItem();         filemenu.Text = "&File";         menu.MenuItems.Add(filemenu);             MenuItem open = new MenuItem();             open.Text = "&Open";             open.Select += new EventHandler(ShowInfo);             filemenu.MenuItems.Add(open);             MenuItem save= new MenuItem();             save.Text = "&Save";             save.Select += new EventHandler(ShowInfo);             filemenu.MenuItems.Add(save);             MenuItem exit= new MenuItem();             exit.Text = "E&xit";             exit.Select += new EventHandler(ShowInfo);             filemenu.MenuItems.Add(exit);         this.Menu = menu;     }     static void Main()     {         Application.Run(new menuapp());     } } 

Figure 3.1.6 shows the menus.cs program in action.

Figure 3.1.6. The Select event handler in action.

graphics/0301fig06.gif

Menu Layout

Menus are built up from MenuItem components . These can be arranged across the screen on the menu bar, and are most often arranged vertically in drop-down menus. You can change the default layout of MenuItem s to give a different UI style.

The Break and BarBreak methods are used to create menus that are arranged horizontally rather than vertically. Setting the BarBreak property in a MenuItem causes the item to be drawn in a new column. BarBreak adds a vertical separator bar to the menu between the columns . Break makes a new column but doesn't add the vertical bar. The modifications to the menus.cs code on lines 14 and 20 in the following result in the change seen in Figure 3.1.7.

Figure 3.1.7. The BarBreak property.

graphics/0301fig07.gif

 1:     MenuItem filemenu = new MenuItem();  2:     filemenu.Text = "&File";  3:     menu.MenuItems.Add(filemenu);  4:  5:         MenuItem open = new MenuItem();  6:         open.Text = "&Open";  7:         open.Select += new EventHandler(ShowInfo);  8:         filemenu.MenuItems.Add(open);  9: 10:         MenuItem save= new MenuItem(); 11:         save.Text = "&Save"; 12:         save.Select += new EventHandler(ShowInfo); 13:         filemenu.MenuItems.Add(save); 14:         save.BarBreak=true; 15: 16:         MenuItem exit= new MenuItem(); 17:         exit.Text = "E&xit"; 18:         exit.Select += new EventHandler(ShowInfo); 19:         filemenu.MenuItems.Add(exit); 20:         exit.Break=true; 21: 

Similarly, the code changes to lines 14 and 20 in the following result in the menu style shown in Figure 3.1.8.

Figure 3.1.8. The Break Property in use.

graphics/0301fig08.gif

 1:     MenuItem filemenu = new MenuItem();  2:     filemenu.Text = "&File";  3:     menu.MenuItems.Add(filemenu);  4:  5:         MenuItem open = new MenuItem();  6:         open.Text = "&Open";  7:         open.Select += new EventHandler(ShowInfo);  8:         filemenu.MenuItems.Add(open);  9: 10:         MenuItem save= new MenuItem(); 11:         save.Text = "&Save"; 12:         save.Select += new EventHandler(ShowInfo); 13:         filemenu.MenuItems.Add(save); 14:         //save.BarBreak=true; 15: 16:         MenuItem exit= new MenuItem(); 17:         exit.Text = "E&xit"; 18:         exit.Select += new EventHandler(ShowInfo); 19:         filemenu.MenuItems.Add(exit); 20:         exit.Break=true; 21: 

Each time you set the Break property, the MenuItem is placed in a new column.

Right-to-Left Menus

To cater to cultures that read right-to-left or to add an unconventional style to your menus, you can modify the menu's RightToLeft property.

 1: MainMenu menu = new MainMenu(); 2: menu.RightToLeft=RightToLeft.Yes; 3: MenuItem filemenu = new MenuItem(); 4: filemenu.Text = "&File"; 

Adding line 2 to resize.cs results in the effect seen in Figure 3.1.9.

Figure 3.1.9. Right-to-left reading menus.

graphics/0301fig09.gif

Creating and Using a Context Menu

A context menu is a floating menu that can pop up wherever it's needed for selections in a particular editing or user interface context. The convention is for the context menu to appear in response to a right-mouse button click.

Windows Forms follows this convention. The application has a ContextMenu property that, like its MainMenu counterpart , is available from the top-level application form.

Adding, showing, or modifying the appearance of a context menu and specifying its handler are largely the same as the main menu. The following adds a context menu with three items to the main window of the resize.cs form:

 ContextMenu cmenu = new ContextMenu(); cmenu.MenuItems.Add(new MenuItem("&First")); cmenu.MenuItems.Add(new MenuItem("&Second")); cmenu.MenuItems.Add(new MenuItem("-")); cmenu.MenuItems.Add(new MenuItem("&Third")); this.ContextMenu=cmenu; 

A simple right mouse click will bring up the context menu.

Replacing, Cloning, and Merging Menus

A common practice in Windows applications is to change menus according to the data displayed in the client window. To save you from having to create and destroy menus on-the-fly , .NET allows you to swap out menus and create new ones by merging one or more predefined menu hierarchies.

Listing 3.1.10 shows a simple application that constructs several menus and then combines them in different ways according to selections made by the user.

Listing 3.1.10 menuswop.cs : Manipulating, Cloning, and Merging Menus
 1: using System;   2: using System.Drawing;   3: using System.ComponentModel;   4: using System.WinForms;   5:   6: namespace Sams {   7:   8: class menuswop : System.WinForms.Form   9: {  10:     MainMenu m_menu;  11:     MenuItem m_editmenu,m_menumenu,m_switchitem,m_showsecond,m_merge;  12:     MenuItem m_playmenu;  13:  14:     bool m_bswop;  15:     bool m_bshowsecond;  16:     bool m_bmerge;  17:  18:     // private helper function for the BuildMenu function.  19:     void addmenuitem(MenuItem menu, string s)  20:     {  21:         MenuItem temp=new MenuItem(s);  22:         temp.Enabled= false;  23:         menu.MenuItems.Add(temp);  24:     }  25:  26:     // This builds a menu structure from copies  27:     // of the originals using CloneMenu.  28:     void BuildMenu()  29:     {  30:         m_menu=new MainMenu();  31:         m_menu.MenuItems.Add(m_menumenu.CloneMenu());  32:  33:         if(m_bmerge) // when we merge...  34:         {  35:             MenuItem temp=new MenuItem();  36:  37:             if(!m_bswop)  38:             {  39:                 addmenuitem(temp,"Edit");  40:                 temp.MergeMenu(m_editmenu.CloneMenu());  41:             }  42:             else  43:             {  44:                 addmenuitem(temp,"Play");  45:                 temp.MergeMenu(m_playmenu.CloneMenu());  46:             }  47:  48:             temp.MenuItems.Add(new MenuItem("-"));  49:  50:             if(m_bshowsecond)  51:             {  52:                 if(!m_bswop)  53:                 {  54:                     addmenuitem(temp,"Play");  55:                     temp.MergeMenu(m_playmenu.CloneMenu());  56:                 }  57:                 else  58:                 {  59:                     addmenuitem(temp,"Edit");  60:                     temp.MergeMenu(m_editmenu.CloneMenu());  61:                 }  62:             }  63:  64:             temp.Text = "&Merged";  65:             m_menu.MenuItems.Add(temp);  66:  67:         }  68:         else // when we dont merge...  69:         {  70:             if(!m_bswop)  71:             {  72:                 if(m_bshowsecond)  73:                 {  74:                     m_menu.MenuItems.Add(m_editmenu.CloneMenu());  75:                 }  76:                 m_menu.MenuItems.Add(m_playmenu.CloneMenu());  77:             }  78:             else  79:             {  80:                 if(m_bshowsecond)  81:                 {  82:                     m_menu.MenuItems.Add(m_playmenu.CloneMenu());  83:                 }  84:                 m_menu.MenuItems.Add(m_editmenu.CloneMenu());  85:             }  86:         }  87:  88:         this.Menu = m_menu;  89:     }  90:  91:     //This method sets or resets the checks on menu items  92:     //note how the MenuItem collection is accessible as an array.  93:     void PopupMenuMenu(Object sender, EventArgs e)  94:     {  95:         m_menu.MenuItems[0].MenuItems[0].Checked = m_bswop;  96:         m_menu.MenuItems[0].MenuItems[1].Checked = m_bshowsecond;  97:         m_menu.MenuItems[0].MenuItems[2].Checked = m_bmerge;  98:     }  99: 100:     // The event handler for the switch menu entry 101:     void OnSwitchMenu(Object sender, EventArgs e) 102:     { 103:         m_bswop = !m_bswop; 104:         BuildMenu(); 105:     } 106: 107:     //The event handler for the show menu entry 108:     void Onshowsecond(Object sender, EventArgs e) 109:     { 110:         m_bshowsecond = !m_bshowsecond; 111:         BuildMenu(); 112:     } 113: 114:     //The event handler for the merge menu entry 115:     void OnMerge(Object sender, EventArgs e) 116:     { 117:         m_bmerge = !m_bmerge; 118:         BuildMenu(); 119:     } 120: 121:     public menuswop() 122:     { 123:         // setup a main menu 124:         m_menumenu = new MenuItem("&Menu"); 125:         m_menumenu.Popup += new EventHandler(PopupMenuMenu); 126: 127:         //Create the switch item. 128:         m_switchitem=new MenuItem("&Switch"); 129:         m_switchitem.Click+=new EventHandler(OnSwitchMenu); 130:         m_menumenu.MenuItems.Add(m_switchitem); 131: 132:         m_showsecond = new MenuItem("&Show"); 133:         m_showsecond.Click+= new EventHandler(Onshowsecond); 134:         m_menumenu.MenuItems.Add(m_showsecond); 135: 136:         m_merge = new MenuItem("&Merge"); 137:         m_merge.Click += new EventHandler(OnMerge); 138:         m_menumenu.MenuItems.Add(m_merge); 139: 140:         // create a second menu 141:         m_editmenu=new MenuItem("&Edit"); 142:         m_editmenu.MenuItems.Add(new MenuItem("Cut")); 143:         m_editmenu.MenuItems.Add(new MenuItem("Copy")); 144:         m_editmenu.MenuItems.Add(new MenuItem("Paste")); 145: 146:         // and an alternative. 147:         m_playmenu=new MenuItem("&Play"); 148:         m_playmenu.MenuItems.Add(new MenuItem("Normal")); 149:         m_playmenu.MenuItems.Add(new MenuItem("Fast Forward")); 150:         m_playmenu.MenuItems.Add(new MenuItem("Reverse")); 151: 152:         m_bshowsecond=true; 153: 154:         //Now build the menu from its parts. 155:         BuildMenu(); 156: 157:     } 158: 159:     public static void Main() 160:     { 161:         Application.Run(new menuswop()); 162:     } 163: } 164: 165: } // end of Sams namespace 

In this listing you can see that initially the menu creation process is normal, but that no menus are actually added to the MenuItem lists of a parent. The Edit and Play menus are kept separate.

The BuildMenu function on line 28 creates a new main menu and assigns it to the application's main menu. This will cause the GC to delete all of the submenus and entries from the main menu. BuildMenu then goes on to create the menu order or merge the two submenus into one, depending on the settings of the class member variables .

This technique allows you to create an initial set of menu items with all their handlers and settings in place, and then use them in many combinations without having to keep track of them or reset them to default values.

In Listing 3.1.10 the merge is very simple. There are however, more complex ways that MenuItem s can be combined. The MenuItem has a merge order property so that when they are merged into another menu, they will sort themselves into a specific sequence. For example, you might want to have a File menu on which functionality is grouped according to the file type or system resources. With the menu merge order, you can ensure that common functions are first in the menu and less common ones are last. To illustrate the merge order functionality, Listing 3.1.11 shows a program in which the menu sorts itself according to the popularity of the selections.

Listing 3.1.11 menuorder.cs : On-the-Fly Menu Reordering and Merging
 1: using System;  2: using System.Drawing;  3: using System.ComponentModel;  4: using System.WinForms;  5:  6: namespace Sams {  7: class menuorder : System.WinForms.Form  8: {  9:     MainMenu m_menu; 10:     MenuItem m_workingmenu; 11:     MenuItem m_menuentry; 12: 13:     // this event handler is called whenever an item is used 14:     void OnUsed(Object sender, EventArgs e) 15:     { 16:         for(int i=0;i<m_menuentry.MenuItems.Count;i++) 17:             m_menuentry.MenuItems[i].MergeOrder ++; 18: 19:         MenuItem m=(MenuItem)sender; 20: 21:         m.MergeOrder--; 22: 23:         if(m.MergeOrder < 0) 24:             m.MergeOrder = 0; 25: 26:     } 27: 28:     // this event handler is also invoked. You could have 29:     // many event handlers attached to the Click sources 30:     void OnClicked(Object sender, EventArgs e) 31:     { 32:         MenuItem m=(MenuItem)sender; 33:         MessageBox.Show("You clicked "+m.Text); 34:     } 35: 36:     //As a menu is popped up it is constructed on the fly. 37:     void OnPopup(Object sender, EventArgs e) 38:     { 39:         m_menu.MenuItems.Clear(); 40:         m_workingmenu.MenuItems.Clear(); 41:         m_workingmenu.MergeMenu(m_menuentry); 42:         m_menu.MenuItems.Add(m_workingmenu); 43:     } 44: 45:     // Sets up the initial menu text and orders. 46:     public menuorder() 47:     { 48: 49:         string[] s=new string[8]{ "Cats","Dogs","Elephants","Geese", "Mooses","Rats", graphics/ccc.gif "Giunea-pigs","Horses"} ; 50: 51:         m_menu = new MainMenu(); 52:         m_menuentry = new MenuItem("&Menu"); 53:         m_menuentry.Popup += new EventHandler(OnPopup); 54: 55:         m_workingmenu = new MenuItem(); 56: 57:         for(int i=0;i<8;i++) 58:         { 59:             MenuItem temp = new MenuItem(s[i]); 60:             temp.MergeOrder=i; 61:             temp.Click+=new EventHandler(OnUsed); 62:             temp.Click+=new EventHandler(OnClicked); 63:             m_menuentry.MenuItems.Add(temp); 64:         } 65: 66:         m_workingmenu.MergeMenu(m_menuentry); 67:         m_menu.MenuItems.Add(m_workingmenu); 68:         this.Menu = m_menu; 69:     } 70: 71:     // instantiates and runs the application. 72:     public static void Main() 73:     { 74:         Application.Run(new menuorder()); 75:     } 76: } 77: 78: } 

This listing also illustrates how you can add more than one event handler to a Windows Forms Click . The same is true for the Select , Popup , and all other events.

Adding Sub Menus

MenuItem objects in Windows Forms have their own MenuItem collections. This allows you to create a hierarchical structure of menus that have their own cascading child menus within them. The following listing illustrates this process.

 MenuItem filemenu = new MenuItem(); filemenu.Text = "&File"; menu.MenuItems.Add(filemenu);     MenuItem open = new MenuItem();     open.Text = "&Open";     filemenu.MenuItems.Add(open);     MenuItem print= new MenuItem();     print.Text = "Print...";     filemenu.MenuItems.Add(print);         MenuItem temp= new MenuItem();         temp.Text = "Pre&view";         print.MenuItems.Add(temp);         temp= new MenuItem();         temp.Text = "To &File";         print.MenuItems.Add(temp);     MenuItem exit= new MenuItem();     exit.Text = "E&xit";     filemenu.MenuItems.Add(exit); 

As before, the indentation shows the menu level. Figure 3.1.10 shows the menu in action.

Figure 3.1.10. Submenus in action.

graphics/0301fig10.gif

I l @ ve RuBoard


C# and the .NET Framework. The C++ Perspective
C# and the .NET Framework
ISBN: 067232153X
EAN: 2147483647
Year: 2001
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net