首页 > 代码库 > 第八章 用户界面(四)
第八章 用户界面(四)
第八章 用户界面(四)
处理 WinForms 事件和事件模块
在第七章我们讨论过事件(Event)模块,它能够用于处理 WinForms 中的事件。当处理 WinForms 中的事件时,通常会遇到没有完全符合想要事件的情况。例如,当鼠标的左、右键单击时会触发MouseButton 事件,但是,我们可能只希望它响应鼠标左键的单击。这时,用 Event.filter 函数可能会很有用,用它创建一个新的事件,只响应鼠标左键的单击。看下面例子的演示:
openSystem.Windows.Forms
let form =
// create a new form
let temp = new Form()
// subscribe the mouse click event filtering so it only
// reacts to the left button
temp.MouseClick
|> Event.filter (fun e-> e.Button = MouseButtons.Left)
|> Event.add (fun _-> MessageBox.Show("Leftbutton")|> ignore)
// return the form
temp
Application.Run(form)
这里,函数filter用函数参数检查鼠标左键是否按下,结果事件通过管道传递给 listen 函数,把事件处理程序加到事件中,[ 这一段应该是忘记改了,从程序来看,已经使用事件的 add 函数了] 就如同调用事件的Add 方法一样。可以在事件处理程序中使用 if 表达式来实现,但是,这个技术有它的优势,能够把控制事件触发的逻辑和事件本身发生的事情分离出来。如果愿意,几个事件处理程序能够重用这个新事件。
清单 8-3 演示了如何使用几个事件函数创建一个简单的画图程序(如图 8-5)。这里以另一种方式使用 MouseDown 事件:首先,用它来监视鼠标是否按下;然后,用分区函数(Event.partition)把事件划分到左、右按钮的按下,用它来控制画图的颜色,红和黑:
清单 8-3 用事件实现一个简单的画图程序
open System
open System.Drawing
openSystem.Windows.Forms
let form =
// create the form
let temp = new Form(Text = "Scribble !!")
// some refrence cells to hold the applications state
let pointsMasterList = ref []
let pointsTempList = ref []
let mouseDown = ref false
let pen = ref (new Pen(Color.Black))
// subscribe to the mouse down event
temp.MouseDown.Add(fun _ -> mouseDown := true)
// create a left mouse down and right mouse down events
let leftMouse, rightMouse =
temp.MouseDown
|> Event.partition (fun e -> e.Button =MouseButtons.Left)
// use the new left and right mouse events to choose thecolor
leftMouse.Add(fun _ -> pen := new Pen(Color.Black))
rightMouse.Add(fun _ -> pen := new Pen(Color.Red))
// the mouse up event handler
let mouseUp _ =
mouseDown := false
if List.length !pointsTempList > 1then
let points = List.toArray !pointsTempList
pointsMasterList :=
(!pen, points) :: !pointsMasterList
pointsTempList := []
temp.Invalidate()
// the mouse move event handler
let mouseMove (e: MouseEventArgs) =
pointsTempList := e.Location ::!pointsTempList
temp.Invalidate()
// the paint event handler
let paint (e: PaintEventArgs) =
if List.length !pointsTempList > 1then
e.Graphics.DrawLines
(!pen, List.toArray !pointsTempList)
!pointsMasterList
|> List.iter
(fun (pen, points) ->
e.Graphics.DrawLines(pen, points))
// wire up the event handlers
temp.MouseUp |> Event.add mouseUp
temp.MouseMove
|> Event.filter(fun _ -> !mouseDown)
|> Event.add mouseMove
temp.Paint |> Event.add paint
// return the form object
temp
[<STAThread>]
doApplication.Run(form)
图 8-5. 涂鸦:用事件实现的简单的画图程序
也可以用这种方法把创建的事件发布到窗体的界面上,这样,使用窗体的代码能够利用这些事件。
另外,程序员在处理 Windows 窗体事件时面临的一个很大的问题,就是可用的事件的数量,这是很难做出正确选择的。可能非常奇怪,大多数事件都定义在控件(control)类中,只有少数几个事件专门额外提供。这样使事情变得更容易,因为如果我们使用随控件的事件,那么,它也可以在其他控件上使用。表8-4 提供了Control 类中的常见事件的汇总:
表 8-4 Control 类的事件汇总
事件 | 描述 |
Click | 该事件是由用户单击控件引起。这是一个高级事件,尽管它通常由用户使用鼠标单击引起,当[ 焦点 ] 在控件上时,也可能由按回车键或空格键引起。有一系列事件 MouseDown、MouseClick、MouseUp,提供有关鼠标动作的详细信息。但是,这些事件提供信息只与鼠标动作有关,因此,通常应该处理单击(Click)事件,而不是这些事件;否则,会导致控件不能按用户所期望的方式响应,因为它只响应鼠标单击,而不响应键盘操作。 |
DoubleClick | 该事件由鼠标双击引用。注意,双击的时间间隔由操作系统决定。程序员处理这个事件应该小心,因为每次触发这个事件,而在此之前还要触发单击事件。就是说,既要处理这个事件,还要处理单击事件。 |
Enter | 该事件当控件激活时引起,既可以是用户按 Tab 键进入,也可以由程序调用 Select 或 SelectNextControl,还可以由用户单击鼠标而引起。通常使用此控件是用来提请注意它处于活动状态,比如,把背景设置为不同的颜色。注意,在窗体类中这个事件被抑制,应该用 Activated 事件。 |
Leave | 该事件当控件停用时引起。既可以是用户按 Tab 键离开,也可以由程序调用 Select 或SelectNextControl,还可以由用户鼠标单击其他控件而引起。我们可能会想用此事件进行验证,但不应该用,而应该用 Validating和 Validated 事件。 在窗体类中这个事件被抑制,应该用 Activated 事件。 [ 是否应该是 Dectivate ] |
KeyPress | 该事件是一序列事件中的一部分,用来获得有关键盘状态的详细信息。为了获得第一次按键的详细信息,使用 KeyDown,当键释放时,用 KeyUp。 |
Move | 用户移动控件时引发该事件。 |
MouseHover | 该事件用于发现鼠标是否悬停控件上,能够给用户提供更多有关该控件的信息。对此,事件 MouseEnter、 MouseLeave 也是有用的。 |
Paint | 当 Windows 刷新窗体时引发该事件。如果你想自己绘制控件,应该处理这个事件。更多信息看本章前面的“画 Windows 窗体”。 |
Resize | 用户改变窗体大小时引发该事件。用于调整窗体的布局大小时应该处理这个事件。 |