Making the most of Mouse events
Last updated at 2:49 am UTC on 16 February 2008
Several projects I wrote required me to learn about event and event handling.
And I am a bug tracker so I have gotten suspicious about certain ways of doing things.
Currently I am using the #on:send:to: forms of giving morphs events.
The great advantage is you can create a behavior and then give it to any morph.
The current event handler has some gotchas.
First if all you want to do is something on #mouseMove you will also need to use an
on #mouseDown or on #mouseUp else your more will never recieve the mouse moves (it doesn't get focus).
Secondly only the last argument given to on:send:to:withValue counts. There is only one ivar for arguments rather than one for each event.
Mostly people either use #...withValue: sameArgument for each event they set up for a particular morph. IMHO this is still a bug waiting to happen.
Thirdly, and this is not EventHandlers fault but the way click detection is currently implemented , while on #click and on #doubleClick work they leave some loose ends. I have found ways to avoid them.
What works instead is staying one step ahead of the game.
You have a morph that wants to behave one way if it is clicked and another if it is moved (by dragging).
And what happens when the mouse is released depends on whether the mouse was clicked (no mouseMove) or dragged.
You are not particularly concerned with what happens on mouse down.
You can set up the event handler to look for #click or #startDrag but then you would have to have some way of telling what happened when you received the mouse up.
Also you may wish to do something special the first time the morph is dragged (as opposed to subsequent moves).
I have found some grace in handling this by staying one step ahead of the game.
Here are the distinctions you wish to make
cllickUp (never dragged)
dragUp (finish dragging)
Rather than have mouse up test for what happened and set flags to make the distinciton the event handler can juggle things for you if you just think one step ahead.
At the start you want to look for first drag on #mouseMove and #clickUp on #mouseUp
One of these will happen first.
If the mouse moves then you want to perform
- drag on #mouseMove and
- dragUp on #mouseUp.
So one of the responsibilites of startDrag is to set the eventHandler
to perform #drag and #dragUp instead of #startDrag and #clickUp.
In the same spirit you can insure robust performance by making
mouseDown set the event handler to perform #startDrag or #clickUp (which ever comes next).
if you stay one step ahead of the game it all works swimmingly.
If you choose to be sensitive to double and triple clicks you can use #clickUp
to do a clickDown (on mouseDown) or (click Interupted on mouseMove).
I haven't gotten that far yet. But the scheme should extent itself if desired.
The benifit of this juggling is the avoidence of a ClickStateHandler with attendant bugs and inefficiecies.
The drawback is there is no way to indicate a click timeout interuption or action. (So if you needed that you would have to do it the other way, right?)