|
可以看到,Form类本身具备了处理各种消息的方法,并且每个方法和不同的消息一一对应。我们只需要覆盖其中的不同方法,就可以改变对某个消息的处理方式。 在Form类中,所有以On开头的方法都是处理各种消息的,这些方法都定义为virtual,都可以被子类的同样方法所覆盖。 消息附加参数:EventArgs。 消息都会附加一些参数,例如鼠标消息会附加鼠标指针的坐标,鼠标按键的类型;键盘消息会附加键盘按键的值,键盘组合键值等。这些消息参数被包装为EventArgs类的不同子类的对象,传递给消息处理方法。
![]() 图6 EventArgs类继承图 其中,EventArgs类不具有特殊的属性,仅具有一个静态的Empty属性,引用到了一个EventArgs对象上,表示消息没有额外的参数。也就是说,当我们看到一个消息处理方法的参数为EventArgs类的对象引用,那说明这个方法处理的消息没有特别的消息参数。
如果消息方法的参数是一个EventArgs类的子类对象引用,则说明这个消息附带一些特殊的参数,例如图中的MouseVentArgs类,表示鼠标消息参数,具有坐标属性,鼠标按键属性等。
上述响应窗体事件的方法:继承Form类,覆盖On打头的消息处理方法,根据参数获取消息附加参数。
注意:一般而言,我们再覆盖On系列方法时,都要在第一句使用base.OnXXX调用超类的被覆盖方法一次,因为超类定义的On系列方法是虚拟方法,本身具有方法体,对消息有一些基本的处理,我们需要调用一次。
3 利用EventHandler委托
一个窗体除了On系列方法处理消息外,还有一系列XXXEventHandler类型的事件属性,名称恰好是On系列方法的方法名去掉On。消息处理方法和事件属性之间的关系为:每一个事件处理方法在内部都访问了对应的事件属性,通过这些属性调用了代理的方法(如果有的话)。
EventHandle委托的类型为:
public delegate void EventHandler(object sender, EventArgs e);
其中,sender参数为引发事件的对象,例如本例中的窗体Form对象。e参数为消息参数,即引发该事件的消息的附加参数。EventArgs类型表示没有附加参数。
其它XXXEventHandler委托大体上和EventHandler委托类似,只是参数不为EventArgs,例如处理鼠标消息的MouseEventHandler类型为:
public delegate void MouseEventHandler(object sender, MouseEventArgs e);
重新改动上一节的代码
Program.cs
1 using System;
2 using System.Drawing; 3 using System.Windows.Forms; 4 5 namespace Edu.Study.Graphics.EventHandler { 6 7 static class Program { 8 9 /// <summary> 10 /// 保存键盘按键消息的按键值 11 /// </summary> 12 private static Keys key = Keys.NoName; 13 14 /// <summary> 15 /// 保存鼠标单击消息的坐标值 16 /// </summary> 17 private static Point point = Point.Empty; 18 19 /// <summary> 20 /// 窗体对象 21 /// </summary> 22 private static Form form = new Form(); 23 24 /// <summary> 25 /// 主方法 26 /// </summary> 27 static void Main(string[] args) { 28 form.Height = 600; 29 form.Width = 800; 30 form.Text = "窗体事件"; 31 32 // 将委托方法关联窗体到事件属性上 33 34 // 关联鼠标事件 35 form.MouseDown += new MouseEventHandler(FormMouseDown); 36 // 关联按键事件 37 form.KeyDown += new KeyEventHandler(FormKeyDown); 38 // 关联刷新事件 39 form.Paint += new PaintEventHandler(FormPaint); 40 41 Application.Run(form); 42 } 43 44 static void FormMouseDown(object sender, MouseEventArgs e) { 45 // 将单击时的坐标保存 46 point = new Point(e.X, e.Y); 47 48 // 刷新窗口, 发出窗口重绘消息 49 form.Refresh(); 50 } 51 52 static void FormKeyDown(object sender, KeyEventArgs e) { 53 // 将键盘按键值保存 54 key = e.KeyCode; 55 form.Refresh(); 56 } 57 58 static void FormPaint(object sender, PaintEventArgs e) { 59 // 实例化字体对象 60 // 使用窗体默认字体, 字号30 61 Font font = new Font(form.Font.FontFamily, 30F); 62 63 // 将鼠标坐标绘制在界面上 64 e.Graphics.DrawString( 65 string.Format("{0} : {1}", point.X, point.Y), // 要绘制的字符串 66 font, // 绘制使用的字体 67 new SolidBrush(Color.Red), // 绘制使用的画刷 68 10, 5 // 绘制到屏幕的坐标 69 ); 70 71 // 将键盘按键值转换为字符串 72 string showText = key.ToString(); 73 74 // 实例化字体对象 75 font = new Font(form.Font.FontFamily, 50F); 76 77 // 测量字符串大小(高度、宽度) 78 SizeF size = e.Graphics.MeasureString(showText, font); 79 80 // 获取屏幕中央点 81 PointF pointf = new PointF((float)form.Width / 2F, (float)form.Height / 2F); 82 83 // 计算字符串绘制起始位置 84 pointf.X -= size.Width / 2; 85 pointf.Y -= size.Height / 2; 86 87 // 绘制字符串 88 e.Graphics.DrawString(showText, font, new SolidBrush(Color.Green), pointf); 89 } 90 } 91 } 这一次我们使用了Form对象和它的各类事件属性,执行结果和上一节代码完全相同。
对于一般性的编程,我们可以灵活的使用上述的两种方式,继承或使用事件属性,来为窗体添加我们感兴趣的事件处理方法,让窗体具有更好的功能。
|







骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价