Pontus Magnusson
Pontus Magnusson

Reputation: 651

Listen on event during other event only

How do I listen to MouseMove event, only after I have pressed my mouse button (MouseDown event)

Im basicly looking for Click->Drag->Release functionality in a F# forms application

Upvotes: 1

Views: 123

Answers (3)

Tomas Petricek
Tomas Petricek

Reputation: 243061

This behavior can be nicely captured using the F# async workflows mechanism. I wrote an article about this (implementing exactly drag & drop kind of functionality) where you can find the details - See Programming user interfaces with F# async workflows.

The sample application implements drawing where you push a button, then move the mouse (to define a rectangle) and then eventually release the button:

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 }

The nice thing here is that you can pretty nicely express the logic - wait for MouseDown (inside waitingLoop), then call the drawingLoop function which waits for MouseMove until the button is released (and then transfers the control back to waitingLoop which starts waiting for another mouse down event).

Another version of a similar piece of code is in Phil Trelford's fractal zoom, which uses the same gesture for zooming.

The complete source code is a part of the Chapter 16 source code of Real-World Functional Programming.

Upvotes: 2

FremyCompany
FremyCompany

Reputation: 2840

You can also use something like this:

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)

In a real implementation, you may want to actually do other stuff when the transition starts, stops, and all those things. You may for example want to capture the pointer on target.

Upvotes: 2

Richard
Richard

Reputation: 109045

Attach the event listeners for move and up in the mouse down event, remove it in the up. This does mean the handler method needs to be a method (or you need to keep hold of the delegate used) to pass to the event's remove method.

(If this were for C# I would point you towards Rx—the Reactive Extensions—as this is perhaps the defining example, but I'm unsure how well Rx works with F#.)

Upvotes: 2

Related Questions