Reputation: 651
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
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
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
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