Windows Forms菜单设计全攻略

Windows Forms菜单设计全攻略(上)

www.ouryh.net 银河技术在线║整理时间:2002-2-8║作者: 蔡世友·yesky ║来源: yesky.com ║阅读:670

[前言:] C#不但继承了C++、Java等面向对象的强大功能特性,同时还是继承了VB、Delphi等编程语言的可视化快速开发功能,也称其为当前第一个完全面向组件的语言。虽然微软将把C#语言作为在WEB上开发一种主流工具来推广,但其在传统客户/服务器模式的程序设计中,特别是在微软.Net平台系统下,C#其强大,易用的特性将会成为Windows应用软件开发人员首选工具。

而在Windows程序设计中,菜单作为用户与程序交互的首选工具,那么在.Net中C#又是如何快速的构造Windows Forms中的菜单呢?怎样才能掌握Windows Forms菜单的实质,在程序设计中做到得心应手,为所欲为的进行窗体菜单程序的开发呢?这篇文章将给您最全面的回答。

一、Windows Forms菜单程序简介

我们知道,在Windows程序中,菜单是一个必不可少的程序元素。通过使用菜单,可以把对程序的各种操作命令非常规范有效的表示给用户。一个Windows程序菜单一般包括一个主菜单(主菜单下面包含许多子菜单)及很多弹出式菜单。单击菜单项程序将执行相应的功能;另外在程序窗体的许多地方单击鼠标右键将会弹出一个针对性的快捷菜单(也可以称为弹出式菜单),单击将执行相应的功能,使得软件的应用变得更加简单,更加人性化。Microsoft视窗系统及其应用软件站稳桌面系统及软件的霸主地位,友好的菜单应用立下不小的功劳。

与传统的Windows程序一样,Windows Forms程序中的菜单也包括一般的菜单及弹出菜单两种。一般的菜单主要是指窗体的主菜单及子菜单。菜单从属特性外观及主要功能又可分类:命令式菜单、选择菜单、链接菜单及分隔菜单等等。

大家一定使用过快速开发(RAD)语言工具(如VB、Delphi等)设计过菜单程序。使用这些开发工具,你只需要把用鼠标把菜单控件拖放到窗体上,并通过简单的菜单外观及属性等设置即可完成非常友好的菜单程序开发。在.Net中,C#是支持快速开发的,因此,通过使用相应的开发工具(如Visual Studio .Net)也可以通过简单的鼠标拖放操作完成大部份的菜单程序设计。当然,由于C#的强大的功能,使用.Net提供的菜单类,你也可以通过记事本等纯文本编辑工具就能写出具有良好用户界面的菜单程序。

但是只有在充分掌握Windows Forms菜单的实质以后,我们才能在程序设计中做到得心应手,为所欲为的进行窗体菜单程序的开发。

二、菜单程序使用类及体系结构

在.NET类库中,定义了一个非常庞大的基础类,以供用户在各种编程使用。在这些类中,有几个专为用户编写菜单程序所用的类,通过使用这几个类,你可以设计出自己想要的任何菜单。下面分别进行简单的介绍:

2.1 Windows Forms菜单类体系结构

.Net类库中,菜单类的定义体系结构如下:

  Object
   MarshalByRefObject
    Component
     Menu
      ContextMenu
      MainMenu
      MenuItem

从上面结构中,我们可以看出,菜单程序设计主要用到三个从Menu类继承的类:ContextMenu、MainMenu与MenuItem,它们分别封装了对弹出式菜单、主菜单及菜单项的定义。

另外,.Net类库还提供了一个Menu.MenuItemCollection集合类来方便对各菜单项的管理。其定义如下:

public class Menu.MenuItemCollection:IList,ICollection,Ienumerable;

2.2 System.Windows.Forms.Menu类

该类是一个抽象类,其是各种类型菜单的基类,封装了一个Windows Forms菜单的大部份公共属性。

在菜单应用程序设计中,我们不直接(也不能)使用该类,而是使用其派生类MainMenu、MenuItem、ContextMenu等进行菜单开发;但可以从该类派生出自己更具个性化的菜单。

在该类中有定义了一个非常重要的属性:MenuItems,其表示该对象所包含的菜单项集合。

2.3 System.Windows.Forms.MenuItem类

该类封装了一个菜单项中的各种成员,所有的菜单项都是由MenuItem对象构成的。该类包含了对一个菜单项的详细定义,如菜单项目的各种属性、响应事件及方法等。MenuItem对象是各种菜单的基本元素,在后面我们将详细讲解菜单项的使用。

2.4 System.Windows.Forms.MainMenu类

作为一个窗体主菜单的容器,其实例产生一个窗体的主菜单对象。你可以直接通过该类的构造函数生成MainMenu对象。其构造函数有两种形式:

MainMenu():不带任何参数,将生成一个不带菜单项的主菜单对象。
MainMenu(MenuItem[] menus):带一个菜单项数据参数,将生成一个主菜单对象,并包括参数中拥有的菜单,作为菜单项。
MainMenu的Menu类的基础上,添加了一个属性:RightToLeft,把属性设为RightToLeft.Yes可以使你的主菜单从窗体的右边排到左边(这种表示是一些国家的语言习惯)。
MainMenu对象提供一个方法CloneMenu(),使得用户可以方便的复制主菜单对象。除此之外,还可以通过GetForm()方法查看当前主菜单所在的窗体。

2.5 System.Windows.Forms.ContextMenu类

该类封装了对弹出式菜单各种特性及功能的定义。使用该类,当你在一个控件上点击右键,或者是在窗体的任何一个区域点击右键,将可以弹出一个快捷菜单。

生成一个弹出式菜单对象,可以使用该类有两个构造函数。其中ContextMenu()生成一个不含任何菜单项的弹出式菜单;ContextMenu(MenuItem[] menus)生成一个包括参数中所指定的菜单项的弹出式菜单。

ContextMenu类在Menu的基础上增加了两个属性,其中一个是RightToLeft可以使菜单项从右到左对齐,另一个SourceControl属性返回一个Control值表示当前所显示弹出菜单对应的控件。

在ContextMenu类中,通过Show()方法可以使程序主动显示弹出菜单。当弹出菜单弹出时将引发一个Popup事件,你可以在定义该事件的响应方法使弹出菜单显示前做一些操作;你也可以通过虚拟的OnPopup()方法引发弹出菜单的Popup事件。

2.6 System.Windows.Forms.Menu.MenuItemCollection类

表示系列菜单项(MenuItem)对象的集合,并提供管理集合中元素的各种方法。该类从Object中继承,并通过Ilist、Icollection等接口继承了.Net中关于集合的各种操作,其在.Net类库中说明如下:

public class Menu.MenuItemCollection : IList,ICollection,IEnumerable

通过使用菜单项集合类,你可以使用集合的各种操作方法,从而非常方便的管理一系列的菜单项,如一个主菜单上的所有菜单项及一个主菜单下的所有子菜单等。

同.Net中的所有集合对象一样,该类Count属性返回集合中的菜单项;还可以通过索引(Index)访问集合中的菜单项;你可以通过集合的Add()、AddRange()向集合中加入菜单项对象,也可以通过Remove()及RemoveAt()等方法删除集合中的元素等等。

原作者: 蔡世友·yesky
来 源: yesky.com
共有670位读者阅读过此文

Windows Forms菜单设计全攻略(下)

www.ouryh.net 银河技术在线║整理时间:2002-2-8║作者: 蔡世友·yesky ║来源: yesky.com ║阅读:460

4.2 添加子菜单

在.Net中,菜单项对象模型其实是一个树状的。一个菜单可以通过在其MenuItems集合中添加菜单项,使其拥有下级子菜单;子菜单同样还可以通过相同的方法添加更下一级子菜单。

一个菜单项对象的MenItems将返回一个Menu.MenuItemCollection集合,通过这个集合可以非常方便的管理其中的元素,例如:要添加一个子菜单只需要使用集合的Add()或者AddRange()方法,删除一个项只需要使用Remove()或者是RemoveAt()即可。

下面的代码将为窗体添加一个主菜单,并在主菜单的第一项添加子菜单:

MainMenu Menu1=new MainMenu(new MenuItem[]{new MenuItem("File"),new MenuItem("Edit"),new MenuItem("Tools")});
this.Menu=Menu1;

MenuItem subMenu1=new MenuItem("New");
MenuItem subMenu2=new MenuItem("Open");
MenuItem subMenu3=new MenuItem("Save");

this.Menu.MenuItems[0].MenuItems.Add(subMenu1);
this.Menu.MenuItems[0].MenuItems.AddRange(new MenuItems[]{subMenu2,subMenu3});//使用AddRange()方法添加集合元素

其中this.Menu.MenuItem[0]表示主菜单项1,而this.Menu.MenuItem[0].MenuItems表示主菜单项1下面的子菜单。

4.3 添加弹出式菜单

在.Net中,System.Windows.Forms.Control类是除菜单外的所有窗体控件及可视化元素的基类,在该类中有一个ContextMenu类型的属性ContextMenu,通过设置该属性可以为控件或窗体添加弹出式菜单。方法非常简单,你只需要创建一个ContextMenu对象,并把该对象赋给窗体或控件的ContextMenu属性即可。

前面我们介绍了ContextMenu类有两个构造函数,使用两个构造函数,与MainMenu类似,我们可以通过下面两种方法为控件或窗体添加弹出式菜单。

第一种方法,使用ContextMenu()产生一个不含任何菜单项的ContextMenu(弹出菜单)对象,然后通过该对象的MenuItems属性管理菜单项,如下面的语句为窗体及按钮添加同样的弹出菜单:

ContextMenu Menu1=new ContextMenu();
Menu1.MenuItems.Add(new MenuItem("弹出菜单一"));
Menu1.MenuItems.Add(new MenuItem("弹出菜单二"));

this.ContextMenu=Menu1;
button1.ContextMenu=Menu1;

第二种方法是使用ContextMenu(MenuItem[] menus)构造函数直接生成具有一系列菜单项的弹出式菜单。如下面的例子:

MenuItem menu1=new MenuItem("弹出菜单一");//生成一个菜单项
MenuItem menu2=new MenuItem("弹出菜单二");
MenuItem menu3=new MenuItem("-");//菜单分隔线
MenuItem menu4=new MenuItem("弹出菜单三");

this.ContextMenu=new ContextMenu(new MenuItem[]{menu1,menu2,menu3,menu4,menu5});//为当前窗体添加弹出式菜单

在使用过程中,你还可以通过ContextMenu对象的RightToLeft设置菜单的排列方式,通过SourceControl查看所显示弹出菜单所对应的控件等,还可以通过直接使用对象的Show()方法强制显示弹出菜单等。

以主菜单(MainMenu)对象相似,要访问一个弹出菜单的具体菜项,你可以直接通过Menu.MenuItemCollection集合进行。如下面的语句:

Menu1.MenuItems[0].Text="Test";

this.ContextMenu.MenuItems[0].Text="Test";

五、响应菜单事件

在菜单编程中,我们需要点击菜单项使程序执行一个命令或者是改变菜单的状态等。这样才能使菜单与用户达到有好的交互。这就需要编写菜单事件的响应函数,使其执行相应的功能。

在Windows Forms中,MenuItem为我们提供了很多的事件,比如当你在菜单项上点击时引发的Click事件,在拖动菜单项时引发的DrawItem事件及当选择菜单项时引发的Select事件等。通过为这些事件编写响应方法,我们就可以使用菜单来控制程序了。

那么如何为一个事件添加响应方法呢?在C#中,增加了一个新的数据类型delegate(代表)来解决事件处理问题。代表数据类型非常类似于C语言中的指针,其与指针不同的是,其是代码是安全的,可管理的。通过使用delegate(代表),你可以通过“+=”(加等于)操作符非常容易地为.Net对象中的一个事件添加一个甚至多个响应方法;还可以通过非常简单的“-=”(减等于)操作符取消这些响应方法。如下面为一个按钮(button1)Click事件添加响应方法的代码:

button1.Click+= new System.EventHandler(Test);

其中Test函数说明如下:

private void Test(object sender, System.EventArgs e)
{
    file://想要执行的具体代码。
}

在上面对事件响应方法Test()的定义中,有两个参数,一个分别表示引发事件的对象(object)sender,由于引发事件的对象不可预知的,因此我们把其声明成为object类型,所有的对象都适用;另一个代表引发事件的具体信息(如引发事件时鼠标的x,y值等),由于各种类型的事件中可能不同,这要根据类中事件成员的说明决定。那么在编程中怎么知道使用哪种类型呢,这可以通过查看类中事件的声明,如上面对于Button类Click事件的定义(该定义直接从Control中继承):

public event EventHandler Click;

在上面声明事件的语句中,Eventhandler是一个delegate(代表)类型,其是如下定义的:

public delegate void EventHandler(object sender,EventArgs e);

与所有的.Net对象一样,要为一个菜单项添加Click事件的响应方法也可以通过类似的方法进行,如下所示:

this.Menu=new MainMenu(new MenuItem[]{new MenuItem("File"),new MenuItem("Edit")});
this.Menu.MenuItems[0].Click+= new System.EventHandler(Test);
this.Menu.MenuItems[0].Click+= new System.EventHandler(menuItem2_Click);

private void Test(object sender, System.EventArgs e)
{
    file://想要执行的具体代码。
}
private void MenuItem2_Click(object sender, System.EventArgs e)
{
    MessageBox.Show("你点击了第二个菜单项","提示信息");//弹出一个对话框,显示提示信息。
}

这样,当你点击菜单项时,程序可以执行相应的功能。而要为一个菜单项(如menuItem1)添加DrawItem(拖动)事件响应方法,则可以通过下面的语句实现:

menuItem1.DrawItem+=new System.Windows.Forms.DrawItemEventHandler(MyMethod);//menuItem1为MenuItem对象

private void MyMethod(object sender,DrawItemEventArgs e)//注意函数的弟二个参数
{
    MessageBox.Show("DrawItem事件引发了","提示信息");//弹出一个对话框,显示提示信息。
}

前面我们讲了菜单项是构成各种菜单的基本元素,由于我们添加事件响应方法是直接通过访问菜单项进行的,因此为菜单添加事件响应方法与主菜单或弹出式菜单无关。

六、综合实例

最后,我们使用Visual Studio .Net开发了一个涉及到菜单操作各方面的实例程序,该程序演示了如何通过C#代码在Windows Forms窗体中添加主菜单、如何为窗体添加弹出式菜单、为菜单项添加事件响应方法及管理各菜单项并存取其属性值等。

下面列出其中部份关键的代码及注释:

private void InitializeComponent()//自定义窗体类初始化函数,Visual Studio ..Net自动产生
{
    //这里只列出了部份代码
    this.button4.Text = "删除弹出菜单";
    this.button4.Click += new System.EventHandler(this.button4_Click);

    this.button1.Text = "添加主菜单";
    this.button1.Click += new System.EventHandler(this.button1_Click);

    this.button2.Text = "添加弹出菜单";
    this.button2.Click += new System.EventHandler(this.button2_Click);
    this.button3.Click += new System.EventHandler(this.button3_Click);
}

private void button1_Click(object sender, System.EventArgs e)////当用户点击按钮button1(添加主菜单)时执行该方法
{
    MenuItem menuItem1=new MenuItem();
    MenuItem menuItem2=new MenuItem();
    MenuItem menuItem3=new MenuItem();
    MenuItem menuItem4=new MenuItem();
    MainMenu mainMenu1=new MainMenu();

    // 设置菜单项的显示文本.
    menuItem1.Text = "Edit";
    menuItem2.Text = "Font Size";
    menuItem3.Text = "Small";

    // 设置菜单项的Checked属性为true
    menuItem3.Checked = true;

    // 为菜单定义一个快捷访问键.
    menuItem3.Shortcut = Shortcut.CtrlS;

    // 设置菜单项文本
    menuItem4.Text = "Large";

    // 为菜单定义一个快捷访问键.
    menuItem4.Shortcut = Shortcut.CtrlL;

    // Set the index of the menu item so it is placed below the first submenu item.
    menuItem4.Index = 1;

    // 把菜单menuItem3及menuItem3加到menuItme2的子菜单中.
    menuItem2.MenuItems.Add(menuItem3);
    menuItem2.MenuItems.Add(menuItem4);

    // 把菜单menuItem2加为菜单一的子菜单
    menuItem1.MenuItems.Add(menuItem2);

    // 为窗体添加主菜单
    mainMenu1.MenuItems.Add(new MenuItem("File"));
    mainMenu1.MenuItems.Add(menuItem1);
    mainMenu1.MenuItems.Add(new MenuItem("View"));
    mainMenu1.MenuItems.Add(new MenuItem("Tools"));
    mainMenu1.MenuItems.Add(new MenuItem("Windows"));

    this.Menu=mainMenu1;
    file://为部份菜单项添加Click事件响应方法
    this.Menu.MenuItems[0].Click+=new System.EventHandler(this.Test);
    menuItem3.Click+=new System.EventHandler(this.Test);
    this.Menu.MenuItems[2].Click+=new System.EventHandler(this.Test);
}

private void button2_Click(object sender, System.EventArgs e)//当用户点击按钮button2(添加弹出菜单)时执行该方法
{
    file://为当前窗体添加弹出式菜单
    this.ContextMenu=new ContextMenu(new MenuItem[]{new MenuItem("PopMenu1"),new MenuItem("PopMenu2"),new MenuItem("PopMenu3"),new MenuItem("PopMenu4")});

    file://设置弹出菜单第一项的Click事件响应方法为Test()
    this.ContextMenu.MenuItems[0].Click+=new System.EventHandler(this.Test);
}

private void button3_Click(object sender, System.EventArgs e)//当用户点击按钮button3(删除主菜单)时执行该方法
{
    try
    {
        MenuItem temp=new MenuItem();
        file://把窗体主菜单的最后一项赋给temp对象,注意对象是引用类型
        temp=this.Menu.MenuItems[this.Menu.MenuItems.Count-1];

        file://显示删除的提示信息
        MessageBox.Show("将要删除了菜单:"+temp.Text,"提示信息!");

        file://删除主菜单
        this.Menu.MenuItems.Remove(temp);
    }
    catch
    {
        MessageBox.Show("操作无效,可能是已经没有菜单供您删除!","提示信息");
    }
}

private void button4_Click(object sender, System.EventArgs e)//当用户点击按钮button4(删除弹出菜单)时执行该方法
{
    try
    {
        MenuItem temp=new MenuItem();

        file://取得当前窗体弹出菜单的最后一项的引用
        temp=this.ContextMenu.MenuItems[this.ContextMenu.MenuItems.Count-1];

        file://显示提示信息
        MessageBox.Show("将要删除了菜单:"+temp.Text,"提示信息!");

        // 删除最弹出菜单的最后一项
        this.ContextMenu.MenuItems.Remove(temp);
    }
    catch
    {
        MessageBox.Show("操作无效,可能是已经没有菜单供您删除!","提示信息");
    }
}

private void Test(object sender,System.EventArgs e)
{
    file://当执行时弹出提示信息显示框,注意此句中对sender对象的强制类型转换
    MessageBox.Show("你通过菜单:"+((MenuItem)sender).Text+"执行本程序!","提示信息");
}

执行该程序将为显示一个没有任何菜单的窗体,你可以通过按钮为窗体添加主菜单及弹出式菜单,还可以通过按钮逐个删除菜单项,点击部份菜单项还会看到其Click事件响应方法的运行的提示信息等。如下图所示:

menu9_1

总结

通过学习我们知道,.Net为我们提供了一系列关于菜单程序设计的类,通过这些类你可以构建基本上所有的菜单应用程序。

在.Net中,主菜单及弹出式菜单分别是由MainMenu及ContextMenu类定义;所有的菜单都是由菜单项(MenuItem类)构成,也就是说不管是哪一种类型的菜单,其基本的元素都是MenuItem对象。

除了部分类(如集合类)以外,在Windows Forms中,大部分菜单相关的类都是由Menu类继承而来,在Menu中提供了一个MenuItems的菜单项目集合,通过其可以达到非常方便的管理一个菜单系列中的菜单项(如添加、删除等),还可以构建一个菜单项的下级子菜单等。

与.Net中的其它所有对象一样,要控制菜单执行相应的程序,需要为菜单对象添加事件的响应方法。

最后,大家可以看到,在C# Windows Forms程序中,菜单的使用是非常灵活的,而且结构也是很清晰的。灵活掌握菜单各种类的关系及使用方法,将会使你在Windows Forms中编写菜单程序中得心应手。

点击这里下载本文源程序

原作者: 蔡世友·yesky
来 源: yesky.com
共有460位读者阅读过此文
Contributors: FHL