仅在其他活动期间收听活动

时间:2014-01-08 13:06:17

标签: events f#

只有在按下鼠标按钮(MouseDown事件)后才能收听MouseMove事件

我基本上在F#表单应用程序中寻找Click-> Drag-> Release功能

3 个答案:

答案 0 :(得分:2)

在鼠标按下事件中附加事件监听器以进行移动和向上移动,在向上移除它。这意味着处理程序方法需要是一个方法(或者您需要保持使用的委托)以传递给事件的remove方法。

(如果这是针对C#的,我会指向Rx- Reactive Extensions - 因为这可能是定义的例子,但我不确定Rx与F#的结合程度如何。)

答案 1 :(得分:2)

您也可以使用以下内容:

let setupDrag(target, fn) =
    let isDown = ref false
    target.MouseDown |> Event.add(fun _ -> isDown := true)
    target.MouseMove |> Event.filter(fun _ -> !isDown) |> Event.add(fn)
    target.MouseUp |> Event.add(fun( _ -> isDown := false)

在实际实现中,您可能希望在转换开始,停止和所有这些事情时实际执行其他操作。例如,您可能希望捕获目标上的指针。

答案 2 :(得分:2)

使用F#异步工作流机制可以很好地捕获此行为。我写了一篇关于此的文章(实现完全拖放功能),您可以在其中找到详细信息 - 请参阅Programming user interfaces with F# async workflows

示例应用程序实现绘图,按下按钮,然后移动鼠标(定义矩形),最后释放按钮:

let rec drawingLoop(clr, from) = async {
   // Wait for the first MouseMove occurrence
   let! move = Async.AwaitObservable(form.MouseMove)
   if (move.Button &&& MouseButtons.Left) = MouseButtons.Left then
      // Refresh the window & continue looping
      drawRectangle(clr, from, (move.X, move.Y))
      return! drawingLoop(clr, from)
   else
      // Return the end position of rectangle
      return (move.X, move.Y) }

let waitingLoop() = async {
   while true do
      let! down = Async.AwaitObservable(form.MouseDown)
      let downPos = (down.X, down.Y)
      if (down.Button &&& MouseButtons.Left) = MouseButtons.Left then
         let! upPos = drawingLoop(Color.IndianRed, downPos)
         do printfn "Drawn rectangle (%A, %A)" downPos upPos }

这里的好处是你可以很好地表达逻辑 - 等待MouseDown(在waitingLoop内),然后调用等待drawingLoop的{​​{1}}函数直到按钮被释放(然后将控件转回MouseMove,开始等待另一个鼠标按下事件。)

类似代码的另一个版本位于Phil Trelford's fractal zoom, which uses the same gesture for zooming

完整的源代码是the Chapter 16 source code of Real-World Functional Programming的一部分。