Tuesday, December 22, 2009

11.4 Restrict Mouse Movement to a Specific Region



11.4 Restrict Mouse Movement to a Specific Region


11.4.1 Problem


You'd like to be able to restrict mouse-cursor movement to
certain areas of the current form. You think it would help users of your
application if the mouse stays where it needs to be until they're done with it.
How can you limit mouse movement in Access?


11.4.2 Solution


The Windows API's ClipCursor
subroutine will limit the movement of the mouse to a single form or region on a
form, as you'll see in this solution.


To try out this technique, load and run the frmClip form from
11-04.MDB. This form, shown in Figure 11-5, limits the mouse movement to
the area of the form once you click the large button. If you click the button
again or close the form, code attached to either event frees the mouse cursor to
move anywhere on the screen. If you move the form, Windows frees the mouse
cursor for you.



Figure 11-5. frmClip limits mouse movement to the
area of the form




To use this technique in your own applications, follow these
steps:





  1. Import the module basClipCursor from 11-04.MDB. This
    module contains the function declarations and user-defined types that you'll
    need.



  2. To limit the mouse to a single form, you'll need to get the
    form coordinates and tell Windows to use those coordinates as limits for the
    mouse. To do this, you'll need code something like the following (because this
    code fragment uses Me, it must be in a form's module, not a global
    module):


    Dim typRect as acb_tagRect

    Call acb_apiGetWindowRect (Me.Hwnd, typRect)
    Call acb_apiClipCursor(typRect)



  3. To free the mouse cursor, use code like this:


    Call acb_apiClipCursor(ByVal vbNullString)




See Section 11.4.3 for an example.


11.4.3 Discussion


The ClipCursor API routine
(aliased as acb_apiClipCursor in the code)
expects as its only parameter a user-defined data type consisting of four long
integers representing coordinates of a rectangle. This data type has been
declared for you in basClipCursor as acb_tagRect. This is a common data
structure, used often with API routines that interact with the screen or
printer. It is defined as follows:


Type acb_tagRect
lngLeft As Long
lngTop As Long
lngRight As Long
lngBottom As Long
End Type

When you want to restrict mouse movement, you'll need to
retrieve the coordinates of the current form. You can accomplish this by calling
the GetWindowRect API function (aliased as
acb_apiGetWindowRect in the code), which will
fill in an acb_tagRect structure with the left, top, right, and bottom
coordinates of the window whose handle you pass it. Therefore, by calling
acb_apiGetWindowRect with the handle of the
current form, you'll retrieve the coordinates of that form in pixels:


Dim typRect as acb_tagRect
Call acb_apiGetWindowRect (Me.hWnd, typRect)

Once you've got a structure containing the coordinates of the
current form, you can call ClipCursor and pass
that filled-in structure to it. The sample form combines these API calls, as
shown here:


Private Sub cmdClip_Click(  )
Dim typRect As acb_tagRect
Static sstrCaption As String

' Static variable to keep track of clipping
Static fClip As Boolean

If fClip Then
Me!cmdClip.Caption = sstrCaption
Call acb_apiClipCursor(ByVal vbNullString)
Else
sstrCaption = Me!cmdClip.Caption
Me!cmdClip.Caption = "Free the Mouse!"
Call acb_apiGetWindowRect(Me.hWnd, typRect)
Call acb_apiClipCursor(typRect)
End If
fClip = Not fClip
End Sub

In the sample routine, which is executed each time you click
the large button on frmClip, fClip alternates between True
and False, keeping track of whether mouse clipping is currently in
effect. If it is, the routine calls acb_apiClipCursor
to disable clipping and resets the button's caption. If clipping is not in
effect, the routine stores away the original caption, sets a new one ("Free the
Mouse!"), retrieves the form's coordinates, and finally calls
acb_apiClipCursor to restrict the cursor's
movement.


To end the mouse-cursor restrictions, send a null value to
acb_apiClipCursor. To do that, pass the
vbNullString
intrinsic constant by value. Because the
acb_apiClipCursor procedure has been declared
to accept any type of parameter, you can send it a structure in one call and a
null value in another.


The method presented in this solution is not foolproof in
Access. You're taking control of a feature that Access normally controls itself,
and sometimes the interaction may be unpredictable. In this case, if you
restrict the mouse movement to a single form, but then use the mouse to move or
resize the form, Access will free the mouse for you. Therefore, if you want to
force users to stay on a single form, you're
better off using a modal form instead. If, on the other hand, you're just trying
to ensure that the mouse remains in the area of the form where the users need it
to be, the method described here is appropriate. Restricting the mouse movement
is not meant for every application, but if you want to help your users out a
little, try it.



No comments: