当前位置:文档之家› windows编程技术18C_窗体编程

windows编程技术18C_窗体编程

第18章 C# 窗体编程
Windows窗体(Form,形状/表单)原来是Visual Basic程序的用户界面,后来成为.NET程序的GUI,被Visual Studio中的C#、Visual Basic、F#、MC++和C++/CLI等开发语言工具所使用,后来又从Visual C++ 2005起被引入到MFC编程中。
作为应用程序的基本单元,窗体实质上只是一个(类似于对话框的)简单框架窗口,内含一块空白板(客户区)。开发人员可通过添加控件(包括菜单条、工具条、状态条、计时器和公用对话框等)来创建用户界面,并通过编写代码来操作数据,从而填充这个空白板。为此,Visual Studio提供了一个有助于编写代码的集成开发环境,以及一个针对.NET框架编程的丰富的控件集。通过使用代码来补充这些控件的功能,可以方便快捷地开发所需要的解决方案。
由于时间有限,本章只介绍C# 窗体编程一些基本内容。
相关帮助文档的位置:
* 窗体编程:“库主页\Visual Studio 2010\Visual Studio \创建基于Windows的应用程序\Windows 窗体”。
* .NET类库:“库主页\Visual Studio 2010\.NET Framework类库”中的System、System.Windows.Forms和System.Drawing等命名空间。
图18-1是在窗体编程需要用到的一些.NET类型的继承关系图,涉及的命名空间主要有System.Windows.Forms、System.Drawing和System.Drawing.Drawing2D。
18.1 创建窗体
下面我们以一个简单的窗体交互绘图程序FormDraw为例(参见图18-2),介绍用C# 编写简单窗体程序的全过程。
18.1.1 创建窗体项目
打开“新建项目”对话框(参见图18-3),选左边“已安装的模板”栏的“其他语言\Visual C#”项,再选中间栏的“Windows窗体应用程序”模板。选择父目录位置后,输入项目名称“FormDraw”,去选“为解决方案创建目录”复选框,按“确定”钮关闭对话框。

图18-1 窗体编程中常用.NET类型的层次结构
字体和颜色标明类型所在的命名空间,正常:System、粗体:System.Windows.Forms、
斜体:System.Drawing、粗斜体:System.Drawing.Drawing2D、灰色:https://www.doczj.com/doc/0a1921444.html,ponentModel

图18-2 交互式窗体绘图程序

图18-3 新建项目对话框
1.项目目录和文件
Visual Studio会自动创建名为FormDraw的项目目录,在项目目录中,自动创建的文件有:项目文件——FormDraw.sln(解决方案)和FormDraw.csproj(C# 项目),代码文件——Program.cs(程序入口)、Form1.cs(窗体编程)和Form1.Designer.cs(窗体设计)。
项目目录还自动包含存放项目的目标代码的obj目录和可执行程序的bin目录,这两个目录中都可包含Debug和/或Realse目录,分别存放具体的调试版和/或发行版的二进制程序代码。
项目目录还自动包含了一个存放项目属性的Proporties目

录,包含如下文件:Settings.settings(项目设置,XML文件)、Resources.resx(资源)、AssemblyInfo.cs(程序集代码)和Resources.Designer.cs(资源设计代码)。
2.用户界面与工具箱
IDE会自动打开一个默认的名为“Form1”的空白窗体(Form1.cs[设计]),并打开对应的“工具箱”窗口,供程序员进行窗体设计,参见图18-4。

图18-4 C# 窗体编程界面
窗体设计所用的工具箱内容丰富,除了VB动力包(Visual Basic PowerPacks)栏(5种)、“报表”栏(1种)和“WPF互操作性”栏(1种)的工具外,其余所有可用的工具位于“所有Windows窗体”栏中(只是缺少了“数据”栏中VS2010新增加的“图表”工具),共有66种。其下各栏将这些工具分门别类地列出,包括:“公共控件”(21种)、“容器”(6种)、“菜单和工具栏”(5种)、“数据”(5种)、“组件”(14种)、“打印”(5种)和“对话框”(5种),共计62种,参见图18-5。只有DomainUpDown(域上下)、PropertyGrid(属性网格)、Splitter(拆分条)、HScrollBar(水平滚动条)、VScrollBar(垂直滚动条)和TrackBar(跟踪条)这5种工具没有包含在这些分类栏中。另外,在窗体编程中,工具栏的“对话框编辑器”栏和“常规”栏为空。
3.代码文件内容
自动生成的程序代码,定义了一个与项目同名的命名空间,还定义了用户的应用程序类Program(基类为默认的System.Object)和派生的窗体类Form1(基类为System.Windows. Forms.Form,参见图18-6),后者被定义在两个同名的部分类(分别位于Form1.cs和Form1.Designer.cs者两个代码文件)中。
1)Program.cs
自动生成的Program.cs代码为:

a) 公共控件、容器 b) 菜单和工具栏、数据、组件 c) 打印、对话框、WPF互操作性、
报表、VB动力包
图18-5 窗体工具箱
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace FormDraw
{
static class Program
{
///


/// 应用程序的主入口点。
///

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
该文件中的代码主要是定义了Program类,它包含Main入口主程序。Main方法中最重要的语句为:
Application.Run(new Form1());
它创建窗体Form1对象,并以其为程序界面(主框架窗口)来运行窗体应用程序。
2)Form1.cs
代码文件Form1.cs包含了窗体部分类Form1的一部分定义,用于程序员编写事件处理代码,也是我们今后工作的主要对象。可以在“解决方案

资源管理器”页中,选中“Form1.cs”项后,按鼠标右键,在弹出的浮动菜单中选“查看代码(C)”菜单项,来以源代码方式打开该文件。下面是该文件的初始代码:
using System;
using System.Collections.Generic;
using https://www.doczj.com/doc/0a1921444.html,ponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FormDraw
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
3)Form1.Designer.cs
代码文件Form1.Designer.cs包含了窗体部分类Form1的另一部分定义,用于存放系统自动生成的窗体设计代码。下面是该文件的初始代码:
namespace FormDraw
{
partial class Form1
{
///


/// 必需的设计器变量。
///

private https://www.doczj.com/doc/0a1921444.html,ponentModel.IContainer components = null;

///
/// 清理所有正在使用的资源。
///

/// 如果应释放托管资源,为 true;否则为 false。
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows 窗体设计器生成的代码

///
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
///

private void InitializeComponent()
{
https://www.doczj.com/doc/0a1921444.html,ponents =
new https://www.doczj.com/doc/0a1921444.html,ponentModel.Container();
this.AutoScaleMode =
System.Windows.Forms.AutoScaleMode.Font;
this.Text = "Form1";
}

#endregion
}
}
4.Application类
密封类Application也位于System.Windows.Forms.Form命名空间中,直接派生于System.Object。下面是它的定义:
public sealed class Application
Application类具有用于启动和停止应用程序和线程、启用可视界面、以及处理Windows消息的方法,如下所示:
* Run —— 在当前线程上启动应用程序消息循环,并可以选择使某窗体可见。常用的重载版为:public static void Run (Form mainForm)。
* Exit 或 ExitThread ——停止消息循环。常用的重载版为:public static void Exit ()。
* EnableVisualStyles ——此方法为应用程序启用可视样式。如果控件和操作系统支持视觉样式,则控件将以视觉样式进行绘制。若要使EnableVisualStyles生效,必须在应用程序中创建任何控件之前调用它;EnableVisualStyles 通常是Main函数的第一行。当调用EnableVisualStyles时,无需单独的清单即可启用可视化样式。语法为:public static void EnableVisualStyles ()。
* Se

tCompatibleTextRenderingDefault ——该方法用于设置兼容文本的默认表示方式。语法为:public static void SetCompatibleTextRenderingDefault (bool defaultValue)
* DoEvents ——在您的程序处于某个循环中时处理消息。
* AddMessageFilter ——向应用程序消息泵添加消息筛选器来监视 Windows 消息。
* IMessageFilter ——使您可以阻止引发某事件或在调用某事件处理程序前执行特殊操作。
该类还具有用于获取或设置当前线程的区域性信息的CurrentCultur和CurrentInputLanguage 属性。不能从此类派生新类(密封类)。
18.1.2 修改窗体属性
窗体的属性有很多(参见图18-7),其中常用的有:
* 布局:大小Size——默认为300*300像素,可以通过修改此属性,或直接拖动窗体的边框来改变窗体的尺寸。运行时用户也可以自己改变窗体大小。
* 窗口样式:图标Icon——默认为,可以通过为点击该属性条目右端浏览钮,装入新的图标文件(16*16和32*32像素,*.ico)。也可以自己通过为项目添加新建图标项,来创建新图标资源,如FormDraw.ico (默认位于项目所在目录)。可以通过“项目\添加新项”菜单项(或按对应的快捷键Ctrl+Shift+A)来完成,参见图18-8和9。然后,在窗体设计界面所对应的属性窗口中,将“窗口样式”栏的图标项“Icon”右边的图案,通过其右端的浏览钮来更换。

图18-7 窗体属性
* 设计:名称(Name)——相当于MFC中的ID,对应于窗体的类名。默认为Form1(似VB),可以改成自己喜欢的名称,如DrawForm,回车确认后,系统会自动修改所有相关内容中的该标识符。
* 外观:背景色BackColor——默认为系统的控件色Control(一般为黄灰色,与对话框的背景色相同),可以点击该属性右端的下三角按钮,选择自己喜欢的颜色,如“自定义”页上的白色。参见图18-10。
* 外观:背景图片BackgroundImage——默认无,可以自己为窗体添加背景图。并通过BackgroundImageLayout属性,来设置图片的填充方式(默认为Tile平铺,还可以选择中心Center、伸展Stretch和缩放Zoom)。

图18-8 添加新项对话框

 a) 默认的新图标 b) 自己设计的图标
 图18-9 添加新的图标项
* 外观:光标Cursor——默认为Default(箭头Arrow)。可以选十字Cross,参见图18-11。
* 外观:文本Text——对应于窗体的标题,默认也为Form1,可以改为自己喜欢的标题,如“窗体绘图”。结果窗体如图18-12所示。
1.添加菜单条
与MFC会自动为应用程序编程生成和添加菜单条、工具条和状态条不同,Visual C# 为窗体程序自动生成的只是一个简单的空白框架窗口,菜单条、工具条和状态条等都需要我们自己手工来添加。
选中“Form1.cs[设计]

”页,打开“工具箱”窗口,展开“菜单和工具栏”项,里面有菜单条(MenuStrip)、工具条(ToolStrip)和状态条(StatusStrip)等控件,参见图18-5 b)。它们都是C# 2.0新增加的控件类,分别用来替换老版本中的MainMenu、ToolBar和StatusBar等控件类,参见图18-13。为了兼容性,2.0版中仍然保留了这些老版本中的类,但是建议在编程中使用新的控件类。

图18-11 可选光标 图18-12 窗体外观

图18-13 新老菜单条、工具条和状态条控件类及其基类
选中“工具箱”窗口的“菜单和工具栏”中的“MenuStrip”项,拖放到窗体中,系统则会自动为窗体添加一个停靠在标题条下的菜单条,参见图18-14。并在Form1.Designer.cs 文件的部分窗体类定义的“Windows 窗体设计器生成的代码”区域后自动添加如下一行代码,来定义该菜单条所对应的菜单条类的实例对象menuStrip1:
private System.Windows.Forms.MenuStrip menuStrip1;
可以通过菜单条“属性”窗口中“设计”栏中的名称属性“(Name)”来修改该对象的变量名称,如mainMenuStrip,回车确认后,系统会自动修改项目中的所有相关部分的代码。
2.添加菜单项
可以像在MFC中一样,为菜单条添加菜单项和访问键&X,参见图18-14 a)。但是添加快捷键(shortcut key)、设置选中(checked)状态、添加图片、添加提示串等,C# 都比MFC方便,可以直接利用属性窗口,直观交互式地完成。
在菜单条中 ,除了添加菜单项外,你还可以利用下拉式列表来为菜单条添加分隔符(ToolStripSeparator类的对象,参见图18-18)、文本框和组合框,参见图18-14 b)。

a) 添加菜单项和访问键 b) 添加分隔条、文本框和组合框
图18-14 添加菜单条成员 图18-15 设置快捷键
可以通过在属性窗口底部的“杂项”栏中的“ShortcutKeys”项来设置快捷键(参见图18-15),按回车键完成。注意,设置快捷键后,系统会自动地将它作为默认串显示在菜单项的右端,不需要(也不支持)自己在菜单项自己编写诸如“\tCtrl+N”的显式串。但是可以在属性窗口的“外观”栏的“ShortcutKeyDisplayString”属性中,输入自己的显示串,来代替默认的串。只有在该属性值为空时,系统才会显示默认的快捷键串。
在C# 的窗体编程中,为菜单项添加小图片是非常容易的。只需在属性窗口的“外观”栏的“Image”属性中,单击右端的浏览钮,在弹出的对话框中,按“导入”钮,在弹出的“打开”对话框中,选择要装入图片资源即可,参见图18-16。与图标一样,你也可以自己创建位图资源(12*11像素,*.bmp)后再选入,参见图18-17。一般还需要为图片设置透明色,这可以

通过属性窗口的“外观”栏中的“ImageTransparentColor”属性来进行,方法与前面设置窗体背景色类似。
你也可以选中菜单项后,直接按鼠标右键,在弹出的浮动菜单中,选“设置图像(M)...”菜单项,来设置该菜单项的图片。
注意,MFC会为应用程序自动生成包含“新建”、“打开”等常用按钮的工具条位图文件Toolbar.bmp。但是在Visual C# 的窗体编程中,得我们自己来创建和添加这些位图。不过,你也可以从VS安装目录的“Samples\1033\”子目录的压缩文件“VC2010Samples.zip”的“C++/Language/General/scribble/Images/”子目录中获得。

图18-16 选择菜单项图片

图18-17 添加位图资源新项对话框

图18-18 菜单项、按钮、状态标签和分隔符类及其基类
你还可以利用“属性”窗口的“行为”栏中的“ToolTipText”属性,为菜单项添加鼠标滑过时的文本提示串。
每当你为窗体添加一个菜单项,系统就会自动添加一个对应的菜单项对象(似添加菜单条),如打开菜单项的对象定义为:
private System.Windows.Forms.ToolStripMenuItem 打开OToolStripMenuItem;
它们都是ToolStripMenuItem类(参见图18-18)的实例对象,默认的对象名为:菜单项名+访问键字母+ToolStripMenuItem,如上面的“打开OToolStripMenuItem”。你也可以修改此对象名,如改为open。
3.添加菜单响应
选中菜单项,选择“属性”窗口的事件页,在“操作”栏的“Click”属性中,键入响应方法的名称,如OnFileOpen。回车确认后,系统会自动在Form1.cs文件中的窗体部分类定义中,添加带空方法体的事件处理方法。例如:
private void OnFileOpen (object sender, EventArgs e)
{

}
可以添加自己的处理代码,如打开文件公用对话框,获取用户选择的(带路径的)文件名。这需要先将工具箱窗口的“对话框”栏中的“OpenFileDialog”控件,拖放到窗体。系统会自动为窗体类添加对应的实例对象,默认的名称为openFileDialog1:
private System.Windows.Forms.OpenFileDialog openFileDialog1;
可以属性窗口顶部的下拉式列表中,选择openFileDialog1项,在属性页中修改“设计”栏的“(Name)”属性的值,达到修改该对象名的目的,如改成openFileDlg。则可以编写打开公用文件对话框的代码如下:
private void OnFileOpen(object sender, EventArgs e)
{
if (openFileDlg.ShowDialog() == DialogResult.OK) {
string fn = openFileDlg.FileName;
}
}
类似地,你也可以为“新建”菜单项,添加OnFileNew事件处理方法,并在其中使用MessageBox类的Show静态方法来显示一个弹出式消息对话框。例如:
private void OnFileNew(object sender, EventArgs e)


{
MessageBox.Show("创建新文档!");
}
4.MessageBox类
MessageBox类是System.Object类的直接派生类,位于System.Windows.Forms命名空间中。其Show静态方法的常用重载格式有:
public static DialogResult Show (string text) // 无标题
public static DialogResult Show (string text, string caption) // 含“确定”按钮
public static DialogResult Show (string text, string caption, MessageBoxButtons buttons)
其中,MessageBoxButtons枚举类型,也位于System.Windows.Forms命名空间中,包含表18-1列出的诸枚举成员。
表18-1 枚举类型MessageBoxButtons的成员
成员名称 说明 AbortRetryIgnore 消息框包含“中止”、“重试”和“忽略”按钮。? OK 消息框包含“确定”按钮。? OKCancel 消息框包含“确定”和“取消”按钮。? RetryCancel 消息框包含“重试”和“取消”按钮。? YesNo 消息框包含“是”和“否”按钮。? YesNoCancel 消息框包含“是”、“否”和“取消”按钮。? 例如(参见图18-19):
MessageBox.Show("创建新文档!");
MessageBox.Show("创建新文档!", "提示信息");
MessageBox.Show("创建新文档?", "请选择", MessageBoxButtons.YesNo);

图18-19 MessageBox的不同Show重载方法的输出
5.添加退出菜单项
默认的窗体,是利用关闭窗口来退出应用程序。我们也可以为窗体的“文件”菜单,添加“退出”或“关闭”菜单项,利用应用程序类的Exit静态方法,来退出正在运行的应用程序。具体做法是:
* 在现有的文件菜单项后,添加一个分隔符,参见图18-20 a)。

a) 添加分隔符 b) 添加退出菜单项
图18-20 添加分隔符和退出菜单项
* 添加退出菜单项(参见图18-20 b)):
* 设置其菜单名或其“外观”栏的“Text”属性的值为“退出(&X)”。
* 设置其“杂项”栏“ShortcutKeys”属性的值为Alt+F4。
* [设置其“设计”栏“(Name)”属性的值为exit。]
* 添加鼠标单击事件处理方法:
* 在“属性”的“事件”页 “操作”栏的“Click”项中,输入事件处理的方法名OnExit。
* 在自动生成的空方法体中,添加语句:Application.Exit();
方法的代码为:
private void OnExit(object sender, EventArgs e)
{
Application.Exit();
}
18.1.4 添加工具条与按钮
为窗体添加工具条及其按钮的方法与添加菜单条和菜单项的类似。
1.添加工具条
选中“Form1.cs[设计]”页,打开“工具箱”窗口,展开“菜单和工具栏”项,将“ToolStrip”项,拖放到窗体中,系统则会自动为窗体添加一个停靠在在菜单条下的工具条,参见图18-21 a)。并在Form1.Designer.cs 文件中自动添加定义该工具条所对应的工具条类的实例对象toolStrip1:
private System.Windows.Forms.ToolSt

rip toolStrip1;
它是ToolStrip类(参见图18-13)的实例对象。
也可以通过工具条的“属性”窗口中“设计”栏中的名称属性“(Name)”来修改该对象的变量名称,如toolStrip。回车确认后,系统也会自动修改项目中的所有相关部分的代码。

a) 添加工具条 b) 添加按钮
图18-21 添加工具条与按钮
2.添加按钮
利用工具条的添加新项的下拉式列表,可以为工具条添加多种成员(参见图18-21 b)),常用的是按钮与分隔符(ToolStripSeparator类的对象,参见图18-17)。新添加按钮时,系统也会在Form1.Designer.cs 文件中自动添加一个对应的按钮对象:
private System.Windows.Forms.ToolStripButton toolStripButton1;
它们都是ToolStripButton类(参见图18-18)的实例对象,默认的对象名为:toolStripButtoni。你也可以修改此对象名,如改为openButton。
默认的按钮图片为System.Drawing.Bitmap,可以通过“属性”窗口“外观”栏中的“Image”属性或直接在按钮上按鼠标右键,在弹出的浮动菜单中选“设置图像(M)...”菜单项,来修改(装入或创建)按钮图片,具体方法与为菜单项添加图片类似。最好采用与对应菜单项相同的图片。
你还可以利用“属性”窗口“外观”栏中的“Text”属性或“行为”栏中的“ToolTipText”属性,为按钮添加鼠标滑过时的文本提示串(默认为“toolStripButton i”),如“打开文件”。
3.添加按钮响应
为工具条上的按钮添加消息响应的方法与为菜单条添加菜单项响应的方法类似:选中按钮,选择“属性”窗口的事件页,在“操作”栏的“Click”属性中,利用该属性项右端的下拉式列表,选择对应菜单项的响应方法名,如OnFileOpen,一般不需要键入和创建新的消息响应方法。
4.动态修改按钮颜色
一个设置颜色的按钮,可以让它随着用户选择的颜色而改变。我们的做法是去掉按钮的图片,动态修改其背景色属性。具体步骤为:
* 在工具条中添加按钮,修改其“(Name)”属性(对象名)为“setColButton”。
* 将其“Image”属性改为“(无)”。
* 在窗体类DrawForm的构造函数中,设置其背景色属性为初始颜色。如:
public DrawForm()
{
InitializeComponent();
……
// col为类变量,初值为Color.Green
setColButton.BackColor = col;
}
* 在用户选择新的颜色,设置其背景色属性为当前颜色。如:
private void OnSetCol(object sender, EventArgs e)
{
setColDlg.Color = col;
if (setColDlg.ShowDialog() == DialogResult.OK)
{
col = setColDlg.Color;
……
setColButton.BackColor = col;
}
}
18.1.5 添加

状态条和状态标签
可以为窗体添加状态条,然后再为状态条添加状态标签等成员,用于显示提示信息和各种状态数据,如当前鼠标位置等。
1.添加状态条
选中“Form1.cs[设计]”页,打开“工具箱”窗口,展开“菜单和工具栏”项,将“StatusStrip”项,拖放到窗体中,系统则会自动为窗体添加一个停靠在在窗口底部的状态条,参见图18-22。并在Form1.Designer.cs 文件中自动添加定义该状态条所对应的状态条类的实例对象statusStrip1:
private System.Windows.Forms.StatusStrip statusStrip1;
它是StatusStrip类(参见图18-13)的实例对象。
也可以通过工具条的“属性”窗口中“设计”栏中的名称属性“(Name)”来修改该对象的变量名称,如statusStrip。

图18-22 添加状态条 图18-23 状态条成员与拆分按钮成员
2.添加状态标签
可以添加到状态条中的成员(参见图18-23 a))有状态标签(StatusLabel)、进度条(ProgressBar)、下拉式按钮(DropDownButton)和拆分按钮(SplitButton),其中的拆分按钮又含有若干成员,参见图18-23 b)。
常用的是状态标签,它可以用于显示提示信息和各种状态数据,如当前鼠标位置等。
为状态条添加状态标签时,系统会在Form1.Designer.cs 文件中自动添加一个对应的状态标签对象:
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
它是ToolStripStatusLabel类(参见图18-18)的实例对象。可以为状态标签设置各种相关的属性,还可以在程序的运行过程中,动态修改这些属性的属性值。
3.显示提示信息
为了显示菜单项和工具条按钮等的提示信息,可以在状态条上添加一个状态标签。在对应的“属性”窗口中,进行如下修改:
* 修改其“设计”栏“(Name)”属性(对象名)为promptLabel(默认为toolStripStatusLabel1)。
* 修改其“外观”栏的“BackColor”属性值为“系统”列表中的“Control”(默认与窗体背景色相同,如为“Web”中的“White”)。
* 修改其“外观”栏的“Text”属性值为“就绪”(默认为“toolStripStatusLabel1”)。
* 修改其“外观”栏的“TextAlign”属性值(参见图18-24)为“MiddleLeft”(默认为“MiddleCenter”)。
* 修改其“外观”栏的“Spring”(弹性)属性值为“true”(默认为false)。最后一个属性为true时,该标签会自动伸缩,始终充满状态条的剩余空间。
修改前的样子和修改后的结果参见图18-25。

图18-24 设置文本对齐属性值 图18-25 添加显示提示信息用的状态标签
与MFC不同,C# 窗体中的状态条并不能自动显示菜单项和工具条按钮的提示信息,而必须自己写代码来完成该任务。
例如

,可以为打开菜单和按钮添加同一个“MouseHover(鼠标悬停)” 事件(即鼠标在对应菜单项或按钮上停留一段时间后所触发的事件)的事件处理方法OnFileOpenMouseHover,并为该方法添加设置提示标签文本属性值的语句:
private void OnFileOpenMouseHover(object sender, EventArgs e)
{
promptLabel.Text = "打开文档文件";
}
当然,你也可以通过为菜单项或按钮添加鼠标进入(MouseEnter)或鼠标单击(Click)等事件的处理方法,来显示提示信息。
为了在鼠标离开菜单项或按钮后,还原“就绪”信息,可以添加对鼠标离开(MouseLeave)事件的处理方法。例如:
private void OnFileOpenMouseLeave(object sender, EventArgs e)
{
promptLabel.Text = "就绪";
}
4.显示鼠标位置信息
为状态条分别依次添加名为xLabel、xValLabel、yLabel和yValLabel的标签(需修改“设计”栏的“(Name)”属性值),修改其“外观”栏的“BackColor”属性值为“系统”列表中的“Control”(默认与窗体背景色相同,如为“Web”中的“White”),将它们“外观”栏“Text”属性的值分别改为“x:”、“0000”、“y:”和“0000”,再将其中的xValLabel和yValLabel标签的“行为”栏的“AutoSize”属性值改为“false”,使其大小固定。
为了美观,还可以在yLabel标签之前,插入一个“Text”属性值为单个空格符的标签,将其背景色,也改为“Control”。参见图18-26。

图18-26 添加显示鼠标位置信息的诸状态标签 图18-27 显示鼠标位置信息
为窗体的“MouseMove”事件添加名为“OnMouseMove”的事件处理方法如下:
private void OnMouseMove(object sender, MouseEventArgs e)
{
xValLabel.Text = e.X.ToString();
yValLabel.Text = e.Y.ToString();
}
运行结果如图18-27所示。
如果你仔细观察,就会发现一个奇怪的现象,客户区最顶端的y坐标,并不是0而是49。这是因为,窗体客户区中还包含了位于其顶端的菜单条和工具条,它们各自高24个像素,加起来刚好48像素。我们将在下一节来解决这个问题。
18.2 绘图
窗体采用GDI+绘图,.NET将GDI+的绘图功能主要封装在System.Drawing和System.Drawing.Drawing2D两个命名空间中。前者封装了GDI+的常用功能,后者则封装了GDI+的高级功能。参见图18-28。

图18-28 GDI+中的常用类型及其基类
字体和颜色标明类型所在的命名空间,正常:System、粗体:System.Drawing、
斜体:System.Drawing.Drawing2D、灰色:System.Drawing.Imaging
18.2.1 画板与图形对象
在窗体中,一般是利用GDI+的图形对象,在镶嵌于窗体空白客户区中的画板上绘图。
1.画板
为了使绘图

区域是去掉菜单条、工具条、状态条和滚动条等内容后的窗体空白客户区,我们可以为窗体绘图添加一个Panel(画板/面板/镶嵌板)控件,并使该控件充满空白客户区。具体做法是:
* 选中“Form1.cs[设计]”页,打开“工具箱”窗口,展开“容器”项(参见图18-5 a)),将Panel容器拖入窗体(参见图18-29)。系统会自动创建一个画板对象panel1,可以更名为drawPanel:
private System.Windows.Forms.Panel drawPanel;
* 设置其“布局”栏的“Dock”(停泊)属性为Fill(充满)(默认为None),参见图18-30。
* 设置其“外观”栏的“BackColor”属性为“White”(默认同窗体客户区),参见图18-31。
因为此时,窗体的客户区被画板覆盖,所以原来我们为窗体编写的鼠标移动事件处理方法,现在已经不起作用。解决办法是,将选择窗体的OnMouseMove方法,也选为画板的“MouseMove”事件的处理方法。

图18-29 将画板容器拖入窗体 图18-30 设置画板的 图18-31 设置停泊和背景色
停泊属性为Fill 属性后的画板
2.图形类
.NET的图形类及其他各种相关类、结构、枚举等类型,都与GDI+中的同名。里面的常量、方法、枚举值也几乎完全相同。所以,有了前面的第14章的GDI+基础,现在在.NET的窗体中绘图,那就是小菜一碟了。
.NET框架的图形类Graphics,位于System.Drawing命名空间中。参见图18-27。为了在窗体或画板中绘图,必须先创建对应的图形对象。这可以使用它们从Control类继承下来的CreateGraphics方法:
public Graphics CreateGraphics ()
例如:Graphics graph = drawPanel.CreateGraphics();
有了图形对象,我们就可以使用图形类中各种绘图方法了。例如:
graph.DrawLine(pen, x0, y0, e.X, e.Y);
graph.DrawRectangle(pen, l, t, w, h);
graph.FillRectangle(brush, l, t, w, h);
graph.DrawEllipse(pen, l, t, w, h);
graph.FillEllipse(brush, l, t, w, h);
3.辅助类与结构
与GDI+一样,.NET框架中也有Pen(笔类),Brush([虚拟]刷类)、SoildBrush(实心刷类)、HatchBrush(条纹刷类)、TextureBrush(纹理刷类)、LinearGradientBrush(线性渐变刷类)、PathGradientBrush(路径渐变刷类),Color(颜色结构)、Point[F]([浮点]点结构)、Size[F]([浮点]大小结构)和Rectangle[F]([浮点]矩形结构)等绘图辅助类型。例如:
Point p(10, 20); // 定义点对象
Color col = Color.Red; // 使用颜色常量
// Color color(255, 100, 255); // 错误!
Pen grayPen = new Pen(Color.Gray, 1), // 创建灰色笔
greenPen = new Pen(Color.Green, 3); // 创建绿色笔
// 创建绿色实心刷
SolidBrush greenBrush = new SolidBrush(Color.Green);
与GDI+的C++封装不同的是,这里的几何对象和颜色不再是类

,而是结构。而且Color结构没有构造函数。为了从RGB值来创建Color对象,必须使用Color的公用静态方法FromArgb:
public static Color FromArgb (int argb) // argb为32位的颜色值
public static Color FromArgb (int alpha, Color baseColor) // alpha=0~255为不透明度
public static Color FromArgb (int red, int green, int blue) // RGB分量(A=255)
public static Color FromArgb (int alpha, int red, int green, int blue) // ARGB分量
例如:
Color col1 = Color.FromArgb (255, 100, 255); // 不透明
Color col2 = Color.FromArgb (128, 255, 100, 255); // 半透明
为了获取Color对象中的ARGB分量,可以使用Color结构的下列只读属性:
public byte A { get; }、public byte R { get; }、public byte G { get; }、public byte B { get; }
例如:
Color col = Color.AliceBlue;
MessageBox.Show(string.Format("A = {0}, R = {1}, G = {2},
B = {3}", col.A, col.R, col.G, col.B));
输出结果见图18-32。

图18-32 获取颜色分量 图18-33 EventArgs类及其若干派生类
18.2.2 OnPaint绘图
与MFC的OnDraw和OnPaint消息处理函数相似,在窗体和画板类中也有Paint事件和对应的委托,及事件处理的虚方法。
1.Paint事件及其委托
Paint事件、PaintEventHandler委托和PaintEventArgs 类都位于System.Windows.Forms命名空间中。
Paint事件的定义为:
public event PaintEventHandler Paint
其中,PaintEventHandler委托的定义为:
public delegate void PaintEventHandler (Object sender, PaintEventArgs e)
其中,PaintEventArgs类的定义为:
public class PaintEventArgs : EventArgs, IDisposable
它是EventArgs类的派生类,参见图18-33。
PaintEventArgs类的常用公用属性有:
* ClipRectangle——获取要在其中进行绘画的矩形:public Rectangle ClipRectangle { get; }
* Graphics——获取用于进行绘制的图形:public Graphics Graphics { get; }
2.OnPaint方法
与MFC一样,系统也会在每次需要重绘窗体或画板的客户区时,调用Paint事件的处理方法。
Form类的OnPaint方法的签名为:
protected override void OnPaint (PaintEventArgs e)
Panel类的OnPaint方法的签名为:
protected virtual void OnPaint (PaintEventArgs e)
我们可以为(窗体或)画板添加自己的Paint事件的处理方法,一般取名为OnPaint,但是也可以使用其他名称。具体做法是:
* 选中“Form1.cs[设计]”页,选中窗体或嵌入其客户区的画板。在对应“属性”窗口,选事件页。
* 在“外观”栏中的“Paint”事件项中,输入事件处理方法名(如OnPaint)后回车。则系统会在代码文件Form.cs中自动生成如下空方法体:
private void OnPaint(object sender, PaintEventArgs e)
{

}
* 在方法添加绘图代码。如:
//base.OnPaint(e); // 一般不能调用被覆盖的基类方法

Graphics graph = e.Graphics;
graph.DrawEllipse(pen, 0, 0, 100, 50);
18.2.3 异或绘图
在MFC中,我们可以利用GDI的SetROP2函数,设置绘图模式为异或(R2_XORPEN),来进行异或画图,以达到擦除而不破坏背景的目的,从而可实现交互绘图中的动态图形动画。在Visual C++中使用GDI+进行交互绘图时,也可以先利用MFC的异或绘图功能来实现异或画图,然后再利用GDI+来完成最后的成图。
但是在C# 中,不能使用MFC,也不能直接调用Windows API中的GDI功能,而GDI+本身又没有异或绘图的能力,所以要在.NET的窗体中实现异或绘图,得另想他法。
1.调用DLL中的非托管函数
C# 是为.NET设计的,.NET是为组件编程设计的,所以我们可以想办法,将位于动态链接库gdi32.dll中的GDI功能,打包成组件后再在C# 中使用。为此,我们需要利用.NET框架中System.Runtime.InteropServices(交互服务)命名空间中的DllImportAttribute类的属性化方法DllImport,将DLL中的非托管函数声明为外部的静态方法,供C# 来使用。
DllImport属性的常用格式为:
[System.Runtime.InteropServices.DllImport("*.dll")]
extern static 其他访问修饰符 函数签名
例如:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern int SetROP2(IntPtr hdc, int nDrawMode);
2.GDI类
我们在Form1类中定义了一个嵌入的GDI类,将我们所要用的GDI函数,都声明为内部(internal)静态(static)的外来(extern)方法:
public partial class Form1 : Form {
……
enum DrawTypes {line, rect, ellipse}
DrawTypes drawType = DrawTypes.line;
bool mouseDown = false, drawn = false;
int x0, y0, x, y;
SolidBrush brush = new SolidBrush(Color.Red);
Pen pen = new Pen(Color.Green, 5);
public class GDI
{
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern IntPtr CreatePen(
int fnPenStyle,
int nWidth,
uint crColor
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern IntPtr GetStockObject(
int fnObject
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern IntPtr SelectObject(
IntPtr hdc,
IntPtr hgdiobj
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern bool DeleteObject(
IntPtr hObject
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern int SetBkMode(
IntPtr hdc,
int nBkMode
);
[S

ystem.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern int SetROP2(
IntPtr hdc,
int nDrawMode
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern bool MoveToEx(
IntPtr hdc,
int X, int Y,
out Point point
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern bool LineTo(
IntPtr hdc,
int nXEnd, int nYEnd
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern bool Rectangle(
IntPtr hdc,
int ulCornerX, int ulCornerY,
int lrCornerX, int lrCornerY
);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
internal static extern bool Ellipse(
IntPtr hdc,
int x1, int y1, int x2, int y2
);
}
……
}
其中的GDI函数原型,参考了wingdi.h头文件(默认位于“C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include”目录中)中的定义。与MFC的对应函数相比,主要是增加了首个HDC类型的参数。
因为C# 和.NET中没有DC句柄类型HDC,可以用System命名空间中的(用于表示指针或句柄的平台特定类型的)IntPtr结构来代替GDI中各种对象的句柄(32位无符号整数)。
另外,在GDI中没有MFC的MoveTo函数,而只有MoveToEx函数,它 多了一个输出的点指针参数:
BOOL MoveToEx(HDC hdc, int x, int y, LPPOINT lppt);
我们将GDI中 POINT结构,用.NET中Point结构来代替,函数原型改为:
bool MoveToEx(IntPtr hdc, int X, int Y, out Point point);
例如:
GDI.MoveToEx(hdc, x0, y0, out point);
GDI中还没有MFC的SelectStockObject函数,可以用GetStockObject和SelectObject函数来合作代替。例如(选入空刷):
IntPtr hOldBrush = GDI.SelectObject(hdc, GDI.GetStockObject(5));
3.使用GDI函数
因为定义在我们的GDI类 中的所有GDI函数都是静态的,所以可以直接使用类名来调用。例如:
IntPtr hPen = GDI.CreatePen(2, 0, 0x808080); // 创建灰色单像素点线笔
GDI.LineTo(hdc, e.X, e.Y); // 画直线到点(e.X, e.Y)
这里有三个问题需要解决,一是如何获得DC句柄,二是如何使用GDI中的常量,三是如何设置颜色值。
* 获取DC句柄——我们可以利用GDI+的GetHdc方法来获取DC句柄:
public IntPtr GetHdc ()
例如:
Graphics graph = drawPanel.CreateGraphics(); // 创建图形对象
IntPtr hdc = graph.GetHdc(); // 获取DC句柄
* GDI常量——因为C# 不能包含头文件,所以我们不能直接使用头文件wingdi.h中所定义的各种GDI常量。完美的解决办法是,将它们都定义成GDI类中的

常量或枚举类型中的枚举值;简单的解决办法是,通过头文件或我的课件查找GDI符号常量所对应的具体数值。因为我们并不是实现所有GDI的功能,而只是想用它来实现异或画图,所以采用简单办法就可以了。例如:
* 点线笔风格(参见8.3.3小节的表8-3)符号常量PS_DOT = 2。
* 预定义空刷(参见8.3.4小节的表8-6)符号常量HOLLOW_BRUSH = 5。
* 绘图模式nDrawMode值(参见8.5.2小节的表8-9):异或模式符号常量R2_XORPEN = 7、覆盖模式符号常量R2_COPYPEN = 13。
* 透明背景模式(参见8.5.1小节的表8-8)符号常量TRANSPARENT = 1。
* 颜色——在C# 中不能利用GDI的RGB宏来设置颜色,但是我们只需用到一种颜色——灰色,其RGB分量都是128(0x80),所以对应的COLORREF值为0x808080。
4.例子
下面是简单的交互式绘图中,鼠标移动事件处理方法的代码:
private void OnMouseMove(object sender, MouseEventArgs e) {
if (mouseDown) { // mouseDown为bool型类变量
int l, t, r, b; // 定义矩形坐标的变量
// 创建图形对象
Graphics graph = drawPanel.CreateGraphics();
IntPtr hdc = graph.GetHdc(); // 获取DC句柄
// 定义点对象(用于MoveToEx函数的输出参数)
Point point = new Point(0, 0);
// 创建灰色单像素点线笔
IntPtr hPen = GDI.CreatePen(2, 0, 0x808080);
// 选入灰笔
IntPtr hOldPen = GDI.SelectObject(hdc, hPen);
IntPtr hOldBrush = GDI.SelectObject(hdc,
GDI.GetStockObject(5)); // 选入空刷
GDI.SetBkMode(hdc, 1); // 设置透明背景模式
GDI.SetROP2(hdc, 7); // 设置异或绘图模式
switch (drawType) {
case DrawTypes.line: // 画动态直线
if (drawn) { // 擦除,下同
GDI.MoveToEx(hdc, x0, y0, out point);
GDI.LineTo(hdc, x, y);
}
GDI.MoveToEx(hdc,x0, y0, out point);
GDI.LineTo(hdc, e.X, e.Y);
break;
case DrawTypes.rect: // 画动态矩形
if (drawn) {
l = Math.Min(x0, x); r = Math.Max(x0, x);
t = Math.Min(y0, y); b = Math.Max(y0, y);
GDI.Rectangle(hdc, l, t, r, b);
}
l = Math.Min(x0, e.X); r = Math.Max(x0, e.X);
t = Math.Min(y0, e.Y); b = Math.Max(y0, e.Y);
GDI.Rectangle(hdc, l, t, r, b);
break;
case DrawTypes.ellipse: // 画动态椭圆
if (drawn) {
l = Math.Mi

n(x0, x); r = Math.Max(x0, x);
t = Math.Min(y0, y); b = Math.Max(y0, y);
GDI.Ellipse(hdc, l, t, r, b);
}
l = Math.Min(x0, e.X); r = Math.Max(x0, e.X);
t = Math.Min(y0, e.Y); b = Math.Max(y0, e.Y);
GDI.Ellipse(hdc, l, t, r, b);
break;
}
GDI.SelectObject(hdc, hOldPen); // 选入老笔
GDI.DeleteObject(hPen); // 删除创建的灰笔
GDI.SetROP2(hdc, 7); // 设置覆盖绘图模式
graph.ReleaseHdc(hdc); // 释放DC句柄
x = e.X; y = e.Y; // 记录当前终点
drawn = true; // 设置已绘图为真
}
xValLabel.Text = e.X.ToString(); // 显示鼠标位置信息
yValLabel.Text = e.Y.ToString();
}
其中,fill为表示是否填充的工具条按纽对象的名字(name属性),pen和brush为窗体类的Pen类和SolidBrush类的对象,用于成图的绘制。
18.2.4 鼠标事件
在交互绘图中需要响应鼠标事件,可以从鼠标事件处理方法的输入参数中,获取鼠标位置和拥护按键等信息。例如:
private void OnMouseMove(object sender, MouseEventArgs e) {……}
其中,鼠标事件处理方法的第一个输入参数为触发事件的对象sender,如Windows.Forms. Panel类的对象drawPanel,第二个输入参数则为MouseEventArgs类的实例对象e。
1.MouseEventArgs类
位于System.Windows.Forms命名空间MouseEventArgs(鼠标事件变量)类,为MouseUp、MouseDown和MouseMove事件提供数据,它是从位于System命名空间的EventArgs类派生的,而后者又是直接从System.Object派生的。MouseEventArgs类的常用成员见表18-2。
表18-2 MouseEventArgs类的常用成员
种类 名称 说明 公共
构造函数 public MouseEventArgs (
 MouseButtons button, int clicks,
 int x, int y, int delta) 初始化MouseEventArgs类的新实例。 公共属性 public MouseButtons Button { get; } 获取曾按下的是哪个鼠标按钮。 public int Clicks { get; } 获取按下并释放鼠标按钮的次数。 public int Delta { get; } 获取鼠标轮已转动的制动器数的有符号计数。制动器是鼠标轮的一个凹口。 public Point Location { get; } 获取鼠标在产生鼠标事件时的位置。 public int X { get; } 获取鼠标在产生鼠标事件时的x坐标。 public int Y { get; } 获取鼠标在产生鼠标事件时的y坐标。 其中,最常用的是Button、Location、X和Y等公用只读属性。
2.例子
下面是简单的交互式绘图中,鼠标键按下和松开事件的事件处理方法的代码:
private void OnMouseDown(object sender, MouseEventArgs e) {
mouseDown = true;
x = x0 = e.X;
y = y0 = e.Y;

}
private void OnMouseUp(object sender, MouseEventArgs e) {
if (mouseDown) {
int l, t, w, h;
Graphics graph = drawPanel.CreateGraphics();
if (drawn) { // 擦除
int r, b;
IntPtr hdc = graph.GetHdc();
Point point;
IntPtr hPen = GDI.CreatePen(2, 0, 0x808080);
IntPtr hOldPen = GDI.SelectObject(hdc, hPen);
IntPtr hOldBrush = GDI.SelectObject(hdc,
GDI.GetStockObject(5));
GDI.SetBkMode(hdc, 1);
GDI.SetROP2(hdc, 7);
switch (drawType) {
case DrawTypes.line:
GDI.MoveToEx(hdc, x0, y0, out point);
GDI.LineTo(hdc, x, y);
break;
case DrawTypes.rect:
l = Math.Min(x0, x); r = Math.Max(x0, x);
t = Math.Min(y0, y); b = Math.Max(y0, y);
GDI.Rectangle(hdc, l, t, r, b);
break;
case DrawTypes.ellipse:
l = Math.Min(x0, x); r = Math.Max(x0, x);
t = Math.Min(y0, y); b = Math.Max(y0, y);
GDI.Ellipse(hdc, l, t, r, b);
break;
}
GDI.SelectObject(hdc, hOldPen);
GDI.DeleteObject(hPen);
GDI.SetROP2(hdc, 7);
graph.ReleaseHdc(hdc);
}
switch (drawType) { // 绘图
case DrawTypes.line:
graph.DrawLine(pen, x0, y0, e.X, e.Y);
break;
case DrawTypes.rect:
l = Math.Min(x0, e.X); t = Math.Min(y0, e.Y);
w = Math.Abs(e.X - x0); h = Math.Abs(e.Y - y0);
if (fill.Checked == true)
graph.FillRectangle(brush, l, t, w, h);
graph.DrawRectangle(pen, l, t, w, h);
break;
case DrawTypes.ellipse:
l = Math.Min(x0, e.X); t = Math.Min(y0, e.Y);
w = Math.Abs(e.X - x0); h = Math.Abs(e.Y - y0);
if (fill.Checked == true)
graph.FillEllipse(brush, l, t, w, h);
graph.DrawEllipse(pen, l, t, w, h);
break;
}
mouseDown = false;
}
}
18.3 对话框
.NET的窗体编程中,也有公用对话框和用户对话框。前者都是CommonDialog类的派生类,后者则是Form类的派生类,参见图18-34。

图18-34 公用对话框类和用户对话框类及其基类
其中:不同字

体标明类所在的命名空间,正常:System、
斜体:https://www.doczj.com/doc/0a1921444.html,ponentModel、粗体:System.Windows.Forms
18.3.1 公用对话框
下面以打开文件对话框和颜色对话框为例,来说明公用对话框的使用方法。
1.OpenFileDialog类
打开文件对话框类OpenFileDialog,从文件对话框类FileDialog派生,位于System. Windows.Forms命名空间,用于提示用户打开文件。该类的定义为:
public sealed class OpenFileDialog : FileDialog
可见它为密封类,无法继承此类。OpenFileDialog类的常用成员见表18-3。
表18-3 OpenFileDialog类的常用成员
种类 名称 说明 公共
构造函数 public OpenFileDialog () 初始化OpenFileDialog类的新实例。 公共属性 public bool AddExtension { get; set; }* 获取或设置一个值,该值指示如果用户省略扩展名,对话框是否自动在文件名中添加扩展名。 public override bool CheckFileExists { get; set; } 已重写。获取或设置一个值,该值指示如果用户指定不存在的文件名,对话框是否显示警告。 public bool CheckPathExists { get; set; }* 获取或设置一个值,该值指示如果用户指定不存在的路径,对话框是否显示警告。 public string DefaultExt { get; set; }* 获取或设置默认文件扩展名。 public string FileName { get; set; }* 获取或设置一个包含在文件对话框中选定的文件名的字符串。 [LocalizableAttribute(true)]
public string Filter { get; set; }* 获取或设置当前文件名筛选器字符串,该字符串决定对话框的“另存为文件类型”或“文件类型”框中出现的选择内容。 public string InitialDirectory { get; set; }* 获取或设置文件对话框显示的初始目录。 public bool ReadOnlyChecked { get; set; } 获取或设置一个值,该值指示是否选定只读复选框。 public bool ShowHelp { get; set; }* 获取或设置一个值,该值指示文件对话框中是否显示“帮助”按钮。 public bool ShowReadOnly { get; set; } 获取或设置一个值,该值指示对话框是否包含只读复选框。 [LocalizableAttribute(true)]
public string Title { get; set; }* 获取或设置文件对话框标题。 公共方法 OpenFile 打开用户选定的具有只读权限的文件。该文件由FileName属性指定。 public DialogResult ShowDialog () 已重载。运行通用对话框。(从CommonDialog继承。) 公共事件 FileOk* 当用户单击文件对话框中的“打开”或“保存”按钮时发生。 HelpRequest? 当用户单击通用对话框中的“帮助”按钮时发生。(从CommonDialog继承。) 其中,带星号的是从FileDialog类继承的,最常用的成员有:公用读写属性FileName和Filter(可以用属性窗口设置)、公用方法ShowDialog(注意,不再是MFC中的DoModal)。
ShowDialog方法返回的是DialogResult枚举值,该枚举类型的定义为:
[ComVisibleAttr

ibute(true)] public enum DialogResult
DialogResult枚举的成员见表18-4。
表18-4 DialogResult枚举的成员
成员 说明 Abort 对话框的返回值是Abort(通常从标签为“中止”的按钮发送)。 Cancel 对话框的返回值是Cancel(通常从标签为“取消”的按钮发送)。 Ignore 对话框的返回值是Ignore(通常从标签为“忽略”的按钮发送)。 No 对话框的返回值是No(通常从标签为“否”的按钮发送)。 None 从对话框返回了Nothing。这表明有模式对话框继续运行。 OK 对话框的返回值是OK(通常从标签为“确定”的按钮发送)。 Retry 对话框的返回值是Retry(通常从标签为“重试”的按钮发送)。 Yes 对话框的返回值是Yes(通常从标签为“是”的按钮发送)。 其中常用的是OK。
2.使用打开文件公用对话框
选中“Form1.cs[设计]”页,打开“工具箱”窗口,展开“对话框”项,将 “OpenFileDialog”控件,拖放进窗体。参见图18-5 c)。
系统会自动为窗体类添加对应的实例对象,默认的名称为openFileDialog1:
private System.Windows.Forms.OpenFileDialog openFileDialog1;
可以从设计窗口下部的对象列表或属性窗口顶部的下拉式列表中,选择openFileDialog1项,在属性页中修改“设计”栏的“(Name)”属性的值,达到修改该对象名的目的,如改成openFileDlg。
可以在“属性”窗口“行为”栏的“Filter”属性中,输入文件过滤器,格式似MFC的,如“C# 代码文件|*.cs|所有文件|*.*”,在“数据”栏的“FileName”属性中输入“*.cs”。
还可以修改其他各种属性,其中很多对应于OpenFileDialog类的公共属性。
例如:
if (openFileDlg.ShowDialog() == DialogResult.OK) {
string fn = openFileDlg.FileName;
MessageBox.Show(string.Format("你选择的文件名为:{0}", fn),
"文件名");
}
输出结果如图18-35和图18-36所示。

图18-35 打开文件对话框 图18-36 文件名消息框
3.ColorDialog类及使用
ColorDialog类派生于CommonDialog类,位于System.Windows.Forms命名空间,它是显示可用的颜色以及允许用户定义自定义颜色的一个通用对话框控件。其常用的公用读写属性见表18-5,它们都可以通过“属性”窗口来设置。
表18-5 ColorDialog类的常用公用读写属性
成员 说明 AllowFullOpen 获取或设置一个值,该值指示用户是否可以使用该对话框定义自定义颜色。 AnyColor 获取或设置一个值,该值指示对话框是否显示基本颜色集中可用的所有颜色。 Color 获取或设置用户选定的颜色。 CustomColors 获取或设置对话框中显示的自定义颜色集。 FullOpen 获取或设置一个值,该值指示用于创建自定义颜色的控件在对话框打开时是否可见。 ShowHelp 获取或设

置一个值,该值指示在颜色对话框中是否显示“帮助”按钮。 SolidColorOnly 获取或设置一个值,该值指示对话框是否限制用户只选择纯色。 其中,最常用的属性有Color和FullOpen。
选中“Form1.cs[设计]”页,打开“工具箱”窗口,展开“对话框”项,将 “ColorDialog”控件,拖放进窗体。系统会自动为窗体类添加对应的实例对象,默认的名称为colorDialog1:
private System.Windows.Forms.ColorDialog colorDialog1;
可以从设计窗口下部的对象列表或属性窗口顶部的下拉式列表中,选择colorDialog1项,在属性页中修改“设计”栏的“(Name)”属性的值,达到修改该对象名的目的,如改成setColDlg。
可以将“属性”窗口“外观”栏的“FullOpen”属性值修改为True,还可以修改其他各种属性,其中大多对应于ColorDialog类的公共属性。
例如(其中col、pen和brush皆为类的字段数据成员,输出结果如图18-37所示):
setColDlg.Color = col;
if (setColDlg.ShowDialog() == DialogResult.OK) {
col = setColDlg.Color;
pen = new Pen(col, 3);
brush = new SolidBrush(col);
}
18.3.2 用户对话框
在MFC中,所有的公用对话框和用户对话框都是从CDialog类派生的,但是在.NET中并没有对应的Dialog类。.NET中的公用对话框都是从CommonDialog(公用对话框)类派生的,而后者又是从Component(组件)类派生的,参见图18-34。
那么在.NET中,应该如何设计和定义用户对话框(类)呢?其实.NET中的窗体(Form)本身就是窗口和对话框的混血儿,所以我们可以直接在窗体上添加各种控件,来设计对话框。我们的对话框类实际上就是一个包含许多控件对象的窗体派生类,而且需要调用Form类的公用方法ShowDialog,将对话框窗体显示为模式对话框。
下面我们以一个绘图参数对话框为例(参见图18-38),给出设计和使用用户对话框的主要方法和步骤。

图18-37 颜色公用对话框 图18-38 设置参数用户对话框
1.添加对话框窗体
选“项目\添加新项”(也可以选中“解决方案资源管理器”或“类视图”中的项目名(如FormDraw),按鼠标右键弹出浮动式菜单(参见图18-39),选其中的“添加\新建项”菜单项)。在弹出的“添加新项”对话框(参见图18-40)中,选中“Windows窗体”模板。还可以在对话框底部的“名称(N):”栏中,修改生成的代码文件的文件名(默认为Form2.cs)。最后按“添加”钮关闭对话框。则系统会自动生成新的窗体类(Form2),及对应的代码文件(如Form2.cs),并会打开新窗体供你编辑。参见图18-43。

图18-39 弹出的浮动菜单

图18-40 添加新项对话

相关主题
文本预览
相关文档 最新文档