1、Windows Forms 的高级功能,授课人:余美华,本章主要内容,使用3个常见控件: 菜单:MenuStrip ;ContextMenuStrip 工具栏: ToolStrip ToolTip 状态栏:StatusStrip 创建MDI应用程序; 创建自己的控件;,MenuStrip,MenuStrip 控件时.NET2.0的新功能。使用该控件,可以轻松创建Microsoft Office中那样的菜单。完成本节学习,将能够:创建菜单; 在运行时添加菜单项; 为菜单创建快捷方式; 为菜单项启用Checked属性;,1.主菜单的设计1) 创建菜单的方法可以使用两种方法创建主菜单:一种方法使用M
2、enuStrip类的构造函数实现主菜单的创建;一种简单的方法是通过C#中的MenuStrip控件即菜单设计器实现菜单的创建。 (1) 添加主菜单新建一个Windows应用程序,在工具箱中双击MenuStrip控件或者用鼠标拖放到窗体上,则在窗体的顶部将添加一个菜单。如下左图所示。,MenuStrip,MenuStrip,MenuStrip,(2) 添加子菜单在上图中,单击菜单中“请在此键入”,输入该菜单项的名称为的为“文件”,建立文件子菜单项;然后在该菜单项的下方显示一个标注为“请在此键入”区域,一个位于该菜单项的右方显示标注为“请在此键入”区域,可以选择区域继续添加。 (3) 移动菜单项选中
3、要移动的菜单项,是用鼠标拖动到相应的位置即可。,MenuStrip,(4) 删除菜单项选中要删除的菜单项,单击右键,再弹出式菜单中选中“删除”即可删除该菜单项。 2)MenuItem对象的属性设计 AllowItemReorder属性:当程序运行时,按下键是否允许改变各菜单项的左右排列顺序。默认值为false,当更改该属性值为true时,按下键的同时可以用鼠标拖动各菜单项以调整其在菜单栏上的左右位置。 Dock属性:指示菜单栏在窗体中出现的位置,默认值为Top。,GripStyle属性:是否显示菜单栏的指示符,即纵向排列的多个凹点,默认值为Hidden。当更改该属性值为Visible时,显示位
4、置由GripMargin属性指定。 Items属性:用于编辑菜单栏上显示的各菜单项。单击Items属性后按钮,弹出项集合编辑器对话框,如图所示。,MenuStrip,3)菜单事件建立菜单后,往往要求菜单实现相应的事件处理功能,一般通过菜单项Click事件处理相应的功能,即通过单击菜单项实现程序功能的交互。该事件在以下几种情况下发生:单击菜单项、使用该菜单项相应的快捷键、使用键盘操作时按回车键。,MenuStrip,MenuStrip,小技巧:编辑各菜单项内容时,可以用符号“&”指定该菜单项的组合键,让其后的字母带下划线显示,如编辑菜单项“E&xit”,则会显示为“Exit”,意思是可以直接用“
5、Alt+x”组合键实现与单击该菜单项相同的功能;用符号“-”可以在下拉菜单中显示各项之间的分隔条。,ContextMenuStrip,快捷菜单(也称为上下文菜单)在用户单击鼠标右键会出现在鼠标位置。快捷菜单在鼠标指针位置提供了工作区或控件的选项。 弹出式菜单能以更加灵活的方式为用户提供更加便利的操作,当用户在不同位置单击鼠标右键,则将显示一组不同的菜单项。 ContextMenuStrip控件和MenuStrip都是ToolStripMenuItem ,ToolStripComboBox,ToolStripSeparator和ToolStripTextBox对象的容器。,ContextMenu
6、Strip,注意:该控件是用于为其他控件服务的,不能单独使用。,编辑完成的ContextMenuStrip控件需要在窗体或相关控件的ContextMenuStrip属性中与其建立关联,才可以在程序运行时用鼠标右键单击对应控件,弹出该快捷菜单。,ContextMenuStrip,在运行时为上下文菜单添加项 1)在创建上下文菜单的方法中,创建MenuItem对象,这个对象将会被添加到Controls集合中。MenuItem menuItemNew = new MenuItem(); 2)为每个菜单项设置Text属性。menuItemNew.Text = “ 3) 将菜单项添加到ContextMen
7、uStrip对象的MenuItems集合中;,ContextMenuStrip,1、常用的基本属性 (1)Items属性:用于编辑快捷菜单上的各菜单项。其编辑方式与MenuStrip控件的菜单项编辑相似,都是调用项集合编辑器对话框来生成菜单项的。 (2)Opacity属性:设置快捷菜单的透明度。取值范围为0%100%,默认值为100%,即不透明。注意:该属性只能在代码中才能看到。2、常用的基本事件 (1)ItemClicked事件:快捷菜单中的任何一个菜单项被单击时触发的操作。 (2)Opening事件:快捷菜单打开时触发的操作。,例1 RTF文件编辑器快捷菜单设计(1)新建一个名为Conte
8、xtMenuStripExample的Windows应用程序项目,将Form1.cs重命名为FormContextMenuStrip.cs,调整窗体到适当大小;设置Text属性为“RTF文件编辑器-快捷菜单”。(2)向窗体中添加一个ContextMenuStrip控件、一个RichTextBox控件和一个Label控件,在设计视图下,窗体界面及控件属性如下图所示,其中快捷菜单中各菜单项的Name属性自上而下依次为“大字体(toolStripMenuItem)”、“小字体(toolStripMenuItem)”、“红色字体(toolStripMenuItem)”、“蓝色字体(toolStripM
9、enuItem)”、“绿色字体(toolStripMenuItem)”、“恢复字体大小(toolStripMenuItem)”、“恢复字体颜色(toolStripMenuItem)”、“保存文件(toolStripMenuItem)”。Text属性自上而下依次为“大字体”、“小字体”、“红色字体”、“蓝色字体”、“绿色字体”、“恢复字体大小”、“恢复字体颜色”、“保存文件”。,(3)在FormContextMenuStrip类中添加类一级变量声明。public partial class FormContextMenuStrip : Form/ 这些变量分别用于保存richTextBox1中初
10、始文本的字体设置Color oldColor;int smallSize = 4;FontStyle oldFontStyle;public FormContextMenuStrip()InitializeComponent();,(4)分别双击ContextMenuStrip控件中的各菜单项,添加其Click事件,代码如下:private void 大字体toolStripMenuItem1_Click(object sender, EventArgs e) FontFamily oldFontFamily = richTextBox1.SelectionFont.FontFamily;ri
11、chTextBox1.SelectionFont = new Font(oldFontFamily, 24, oldFontStyle); private void 小字体toolStripMenuItem1_Click(object sender, EventArgs e) FontFamily oldFontFamily = richTextBox1.SelectionFont.FontFamily;richTextBox1.SelectionFont = new Font(oldFontFamily,smallSize, oldFontStyle); private void 红色字体t
12、oolStripMenuItem1_Click(object sender, EventArgs e) richTextBox1.SelectionColor = Color.Red; ,private void 蓝色字体toolStripMenuItem1_Click(object sender, EventArgs e) richTextBox1.SelectionColor = Color.Blue; private void 绿色字体toolStripMenuItem1_Click(object sender, EventArgs e) richTextBox1.SelectionCo
13、lor = Color.Green; private void 恢复字体大小toolStripMenuItem1_Click(object sender, EventArgs e) FontFamily oldFontFamily = richTextBox1.SelectionFont.FontFamily;richTextBox1.SelectionFont = new Font(oldFontFamily, 8, oldFontStyle); private void 恢复字体颜色toolStripMenuItem1_Click(object sender, EventArgs e) r
14、ichTextBox1.SelectionColor = oldColor; ,private void 保存文件toolStripMenuItem1_Click(object sender, EventArgs e) richTextBox1.SaveFile(“d:source.rtf“, RichTextBoxStreamType.RichText); (5)按键编译并执行,尝试利用快捷菜单对richTextBox1中的文本进行各种操作。,备注:关于RichTextBoxStreamType 枚举 指定用于加载和保存 RichTextBox 控件数据的输入流和输出流的类型。,程序运行初始
15、界面,在富文本框中输入文本:计算机世界,选中“计算机世界”,并单击鼠标右键,选择“大字体”命令,上一命令的执行效果,ToolStrip,向ToolStrip控件的作用是为Windows应用程序添加工具栏。工具栏一般由多个按钮、标签等排列组成,通过这些项可以快速地执行程序提供的一些常用命令,比使用菜单选择更加方便快捷。Windows窗体中添加一个ToolStrip控件后,窗体顶端会出现一个工具栏,如下图所示,单击工具栏上的小箭头、弹出下拉菜单,其中每一项都是可以使用在工具栏上的项类型,常用的有Button(按钮)、ComboBox(下拉框)和TextBox(文本框)等控件,单击某项即可添加到工具
16、栏上。,1) 单击鼠标右键ToolStrip控件,在弹出的快捷菜单中单击插入标准项, 则可以快速地在ToolStrip控件上添加如下右图所示的常用按钮,分别表示“新建”、“打开”、“保存”、“打印”、“剪切”、“复制”、“粘贴”和“帮助”等功能。向工具栏上添加了各项之后,再分别设置各项属性,并为各项添加Click事件即可完成工具栏的设置。,ToolStrip,2)在“工具箱”中双击ToolStrip控件;在该控件中添加工具按钮。选中工具栏,在该属性中选择“行为”组,在“行为”组中选择Buttons属性,单击添加按钮,弹出如图所示的集合编辑器。在集合编辑器中添加按钮并设置相应的属性。,ToolS
17、trip,一般来讲,工具栏中的按钮往往与图像相结合,这种方法的实现需要与存放图像的ImageList控件相结合。首先应在窗体中添加“ImageList”控件,在控件中添加相应的图像。其次,设置工具栏的ImageList属性,在该属性的下拉框中选择ImageList控件,最后,打开ToolStrip集合编辑器,设置ImageIndex为每个ToolStripButton按钮选择相应得图像即可。给工具栏中的ToolStripButton控件添加代码实现功能。 编写ToolStrip _ButtonClick事件工具栏中按钮的事件不是通过具体按钮的单击实现的,是通过工具栏的单击事件实现的。通过单击事
18、件中e.Button判断工具栏中按钮执行命令的情况。,ToolStrip,ToolTip控件,ToolTip组件,即信息提示组件,其作用是当鼠标停留在某个与ToolTip组件建立关联的控件上一段时间后,自动显示该控件功能的提示信息。 注意:ToolTip组件是用来为其他控件服务的,不能单独使用。在窗体设计时,将该组件拖入窗体也不会单独显示在窗体中,而是和Timer组件相似显示在窗体的下方。 当向窗体中添加一个ToolTip组件后,该窗体中的其他控件,包括窗体本身,属性对话框中都将会出现一个新的属性“toolTip1上的ToolTip”,如图所示,其中“toolTip1”是所添加ToolTip控
19、件的Name属性值,修改该属性即可使用一个ToolTip组件为窗体中的各个控件添加提示信息。,ToolTip控件,1、常用的基本属性 (1)Active属性:表示ToolTip当前是否处于激活状态。只有Active属性值为true时,所设置的提示信息才会显示。 (2)AutoPopDelay属性:设置提示信息的持续显示时间,默认值为5000ms。 (3)InitialDelay属性:设置鼠标停留在控件上到显示提示信息的时间间隔,默认值为500ms。 (4)ReshowDelay属性:设置鼠标从一个提示区域转移到另一个提示区域时,两个不同的提示信息显示的时间间隔,默认值为100ms。,ToolT
20、ip控件,2、常用的事件Popup事件:显示提示信息时触发的操作。例2 ToolTip组件使用示例。(1)新建一个名为ToolTipExample的Windows应用程序,在解决方案资源管理器中将Form1.cs重命名为FormToolTip.cs,调整窗体至适合大小,设置窗体的Text属性为“ToolTip示例”。(2)向窗体中添加一个ToolTip组件、一个TextBox控件、一个Button控件和一个Label控件,在设计视图下,各控件的布局及相关属性如图所示,ToolTip控件,(3)添加buttonOk的Click事件代码。private void button1_Click(obj
21、ect sender, EventArgs e)labelDisplay.Visible = true;labelDisplay.Text = textBoxInput.Text;textBoxInput.Clear();,(4)按键编译并执行,在文本框中输入一些文本,单击buttonOk按钮,然后将鼠标停留在各控件上一段时间。,程序运行的初始界面,鼠标停留在“文本框”上的提示信息界面,鼠标停留在“命令按钮”上的提示信息界面,在文本框中输入如下图所示的内容,单击“命令按钮”后的程序界面,在这个例子中,是通过修改控件toolTipInformation的ToolTip属性实现信息提示的。除了这种
22、方法之外,还可以利用ToolTip控件的SetToolTip方法来设置提示信息。例如,直接在buttonOk控件的Click事件代码中添加如下语句:this.toolTipInformation.SetToolTip(this.labelDisplay,”显示的是您刚输入的内容”); 这种方法得到的提示信息显示效果和例子中通过属性设置得到的效果相同。,StatusStrip,Windows窗体StatusStrip控件在窗体中作为一个区域使用,此区域通常显示在窗口底部,应用程序可以在这里显示各种状态信息。 StatusStrip控件上通常 有ToolStripStatusLabel 控件,用于
23、显示指示状态的文本或图标,或者有可以用图形显示进程完成状态的ToolStripProgressBar。,SDI MDI 应用程序,基于对话框的应用程序:它们向用户显示一个对话框,该对话框提供了所有功能。(“计算器,扫雷游戏”) 单一文档界面(SDI):这些应用程序向用户显示一个菜单,一个或多个工具栏和一个窗口,在该窗口中,用户可以执行任务。(“记事本”) 多文档界面(MDI):这些应用程序的执行方式与SDI相同,但可以同时打开多个窗口。(“幻灯片,WORD”) 区别:单文档就是一个窗口只能处理一个文档;多文档就是同时可以处理多个,共享工具栏,菜单栏;对话框就是一个提示用户进行选择或者确认的窗体
24、;,MDI,多文档界面(MDI)应用程序使您能同时显示多个文档,每个文档显示在各自的窗口中。 MDI应用程序中常有包含子菜单的“窗口”菜单项,用在窗口或文档之间进行切换。 多文档界面(MDI)应用程序的基础就是MDI父窗体。它是包含MDI子窗体的窗体。 MDI子窗体是多文档界面(MDI)应用程序的必要元素,因为这些窗体时用户交互的中心。,多文档窗口的创建,父窗体:将IsMDIContainer 属性设置为“true”。这将指定该窗体为子窗体的MDI容器。 子窗体:在父窗体中调用子窗体。“newMDIChild.MdiParent = this.newMDIChild.Show();” 活动窗体
25、:父窗体的ActiveMdiChild属性; 活动控件:子窗体的ActiveControl 可在MDI父窗体中使用LayoutMdi方法和MdiLayout枚举重新排列子窗体。,练习1:MDI的创建 ,1)设置一窗体为父窗体:,2)创建子窗口,选择 工程| 添加新项,在打开对话框中选择Windows Form,给项目添加一个新窗体; 3)把新建窗体的MdiParent属性设置为主窗口的一个引用,该窗体就变成子窗口了。不能通过属性面板设置,只能通过代码来设置。public frmChild(MdiBasic.frmCotainer parent)InitializeComponent();thi
26、s.MdiParent =parent;,具体操作:,修改子窗体的构造函数,子窗体的构造函数含有参数parent,4) 设置窗体容器(父窗体),因为必须要告诉MDI容器显示哪个窗,因此要创建一个显示窗体的实例,再对它调用show()方法。public frmContainer()InitializeComponent();MdiBasic.frmChild child=new MdiBasic.frmChild(this);child.show();,修改父窗体的构造函数,练习2:MDI文本编辑器 ,1)利用前面的状态栏示例,把窗体重新命名为frmEditor,把Text属性改为Editor
27、2)给项目添加一个新窗体frmContainer.cs,设置如下属性,3)打开Program.cs文件,在Main方法中修改包含Run语句的代码行:Application.Run(new frmContainer();,4)修改frmEditor窗体的构造函数:public frmEditor(frmContainer parent)InitializeComponent();this.toolStripComboBoxFonts.selectedIndex = 0;this.MdiParent = parent;5) 把菜单项把工具栏的AllowMerge属性改为False;6)给frmCo
28、ntainer窗体添加一个MenuStrip。再在MenuStrip中添加一个菜单项&File。,7)修改窗体frmContainer的构造函数:public frmContainer() InitializeComponent();frmEditor newForm = new frmEditor(this);newForm.show();,创建控件,Visual Studio 提供了一个项目类型Windows Control Library,使用它可以创建自己的控件;两种不同的自定义控件 用户控件或组合控件:这种控件是根据现有控件的功能创建一个新的控件;或通过组合几个现有windows窗体
29、控件的功能,创建复合控件; 定制控件:从头开始创建控件,在创建控件的过程中没有现有的控件可以使用,为支持自动滚动行为的控件定义一个基类,在处理控件时,要考虑许多问题。如果控件不满足条件,人们就不会使用它: 1)在设计期间,控件的操作方式尽可能接近运行期间的操作方式。 2)访问控件的属性应该可以再窗体设计器中以逻辑的方式进行。例如ImagList控件显示了一个对话框,用户可以在对话框中浏览要包含的图像,导入图像后,它们就显示在对话框的一个列表中;自定义控件的创建过程: 1)创建一个新的Windows Forms Control Library 项目;2)打开设计界面,打开空间的属性;3)添加工具
30、箱中的多个控件;4)添加并设置各控件的属性;,5)调试用户控件; 从“文件”菜单中选择添加一个“新的工程”,创建一个Windows应用程序Test.cs。在解决方案资源管理器中就存在两个项目,第一个是创建的用户控件库,以黑体显示,若要运行解决方案,调试程序将此控件项目作为启动项目。这将会失败,因为空间不是一个独立的项目。为了更正这个问题,应该右击项目Test,选择“设为启动项目”; 现在,在工具箱的顶部有一个选项卡有我们定制的控件,Visual Studio 知道解决方案中有Windows 控件库,在其他项目中也可以使用这个库提供的控件。 双击该定制的控件即可添加到窗体上。,练习:LabelT
31、extbox示例,1.创建一个新的Windows Forms Control Library 项目,命名为LabelTextbox。 2.单击设计界面,打开控件的属性。把控件的Name属性改为ctLabelTextbox. 3.双击工具箱中的标签Label,把它添加到用户控件中,将name属性改为lblTextBox,把Text属性设置为Label。 4.双击工具箱中的文本框Textbox,把它的name属性改为txtLabelText.(因在设计期间,不知道如何准确定位控件,故在代码中进行位置定位),确定控件彼此的位置,用户应能决定控件如何定位。为此,要给控件添加两个属性:一为Positio
32、n (枚举类型:Right或者是Below)另外一个是TextboxMargin(int类型,表示控件左边界到文本框的像素数)添加属性:public partial class ctlLabelTextbox:UserControl public enum PositionEnum Right,Belowprivate PositionEnum mPosition = PositionEnum.Right;private int mTextboxMargin = 0;,然后添加Postion属性 public PositionEnum Position get return mPosition
33、;set mPosition = value;MoveControls(); 添加TextboxMargin属性,处理的是一个整数public int TextboxMargin get return mTextboxMargin;set mTextboxMargin = value;MoveControls();,添加事件:1 将控件放至窗体上时,需调用Load事件,用于初始化控件和该控件使用的所有资源,(设置好窗体大小,使之包容控件)2 SizeChanged事件,改变控件大小时,引发该事件。private void ctlLabelTextbox_Load(object sender,
34、EventArgs e)lblTextBox.Text = this.Name; / Add a text to the label/ Set the height of the control.this.Height = txtLabelText.Height lblTextBox.Height ? txtLabelText.Height : lblTextBox.Height;MoveControls(); / Move the controls.private void ctlLabelTextbox_SizeChanged(object sender, EventArgs e)Move
35、Controls();,private void MoveControls()switch (mPosition)case PositionEnum.Below:this.txtLabelText.Top = this.lblTextBox.Bottom;this.txtLabelText.Left = this.lblTextBox.Left;this.txtLabelText.Width = this.Width;this.Height = txtLabelText.Height + lblTextBox.Height;break;case PositionEnum.Right:txtLa
36、belText.Top = lblTextBox.Top;If (mTextboxMargin = 0)int width = this.Width - lblTextBox.Width - 3;txtLabelText.Left = lblTextBox.Right + 3;txtLabelText.Width = width;else txtLabelText.Left = mTextboxMargin;txtLabelText.Width = this.Right - mTextboxMargin;this.Height = txtLabelText.Height lblTextBox.
37、Height ?txtLabelText.Height : lblTextBox.Height;break;,读程序,在没有阅读过一份完整的源代码之前,别指望能写出有多好的程序 读程序必须具备一定的语言基础知识,主要是指语法知识,最起码要能读懂程序的每一行意思有没有程序的设计思想,在这个时期并不重要,只要具备一定的语法基础就可以了 看代码的时候,遇到了不明白的地方再去查相关的资料,补充基础知识再配合源程序的思路,这时的理解才是最深刻的,写程序,刚开始写程序,不要奢望一下子写出很出色的程序来 “万丈高楼平底起”,编程贵在动手,只要动手去写就可以了此外,还要依照自身的能力循序渐进地写 开始的时候写一点功能简单的、篇幅短小的代码,力求简洁、完整,然后在此基础上进行扩充,一点点地添加功能,积累功能代码,积累非常的重要,将平时自己写的和自己已经读通的程序分类保存起来建一个属于自己的代码库,需要相关功能的时候,就到代码库中找相关的代码这样既提高编码的效率又提高了正确率,