Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Macintosh Toolbox Essentials /
Chapter 5 - Control Manager / Using the Control Manager


Responding to Mouse Events in a Control

The Control Manager provides several routines to help you detect and respond to mouse events involving controls. For mouse events in controls, you generally perform the following tasks:

  1. In your event-handling code, use the Window Manager function FindWindow to determine the window in which the mouse-down event occurred.
  2. If the mouse-down event occurred in the content region of your application's active window, use the FindControl function to determine whether the mouse-down event occurred in an active control and, if so, which control.
  3. Call TrackControl to handle user interaction for the control for as long as the user holds the mouse button down. For scroll arrows and the gray areas of scroll bars, you must define an action procedure for TrackControl to use. This action procedure should cause the document to scroll as long as the user holds down the mouse button. For pop-up menus, you pass Pointer(-1) in a parameter to TrackControl to
    use the action procedure defined in the pop-up control definition function. For the scroll box in scroll bars and for the other standard controls, you pass NIL in a parameter to TrackControl to get the Control Manager's standard response to mouse-down events.
  4. When TrackControl reports that the user has released the mouse button with the cursor in a control, respond appropriately. This may require you to use other Control Manager routines, such as GetControlValue and SetControlValue, to determine and change control settings.

These and other routines for responding to events involving controls are described in the next several sections.

Note
The Dialog Manager procedure ModalDialog automatically calls FindWindow, FindControl, and TrackControl for mouse-down events in the controls of alert and modal dialog boxes. You can use the Dialog Manager function DialogSelect, which automatically calls FindWindow, FindControl, and TrackControl, to help you handle mouse events in your movable modal and modeless dialog boxes.

Determining a Mouse-Down Event in a Control

When your application receives a mouse-down event, use the Window Manager function FindWindow to determine the window in which the event occurred. If the cursor was in the content region of your application's active window when the user pressed the mouse button, use the FindControl function to determine whether the mouse-down event occurred in an active control and, if so, which control.

When the mouse-down event occurs in a visible, active control, FindControl returns a handle to that control as well as a part code identifying the control's part. (Note that when the mouse-down event occurs in an invisible or inactive control, or when the cursor is not in a control, FindControl sets the control handle to NIL and returns 0 as its part code.)

A simple control such as a button or checkbox might have just one "part"; a more complex control can have as many parts as are needed to define how the control operates. A scroll bar has five parts: two scroll arrows, the scroll box, and the two gray areas on either side of the scroll box. Figure 5-4 on page 5-7 shows the five parts of a scroll bar.

A part code is an integer from 1 through 253 that identifies a part of a control. To allow different parts of a multipart control to respond to mouse events in different ways, many of the Control Manager routines accept a part code as a parameter or return one as
a result. Part codes are assigned to a control by its control definition function. The standard control definition functions define the following part codes. Also listed are the constants you can use to represent them.
ConstantPart codeControl part
inButton10Button
inCheckBox11Entire checkbox or radio button
inUpButton20Up scroll arrow for a vertical scroll bar, left scroll arrow for a horizontal scroll bar
inDownButton21Down scroll arrow for a vertical scroll bar, right scroll arrow for a horizontal scroll bar
inPageUp22Gray area above scroll box for a vertical scroll
bar, gray area to left of scroll box for a horizontal
scroll bar
inPageDown23Gray area below scroll box for a vertical scroll bar, gray area to right of scroll box for a horizontal
scroll bar
inThumb129Scroll box

The pop-up control definition function does not define part codes for pop-up menus. Instead (as explained in "Creating a Pop-Up Menu" beginning on page 5-22), your application should store the handles for your pop-up menus when you create them.
Your application should then test the handles you store against the handles returned
by FindControl before responding to users' choices in pop-up menus; this is described in more detail later in the next section.

Listing 5-9 illustrates an application-defined procedure, DoMouseDown, that an application might call in response to a mouse-down event. The DoMouseDown routine first calls the Window Manager function FindWindow, which returns two values: a pointer to the window in which the mouse-down event occurred and a constant that provides additional information about the location of that event. If FindWindow returns the inContent constant, then the mouse-down event occurred in the content area of one of the application's windows.

Listing 5-9 Detecting mouse-down events in a window

PROCEDURE DoMouseDown (event: EventRecord);
VAR
   part:       Integer;
   thisWindow: WindowPtr;
BEGIN       {handle mouse-down event}
   part := FindWindow(event.where, thisWindow);
   CASE part OF
      inMenuBar:
         ;  {mouse-down in menu bar, respond appropriately here}
      inContent: 
         IF thisWindow <> FrontWindow THEN
            {mouse-down in an inactive window; use SelectWindow }
            { to make it active here}
         ELSE        {mouse-down in the active window}
            DoContentClick(thisWindow, event);
      {handle other cases here}
   END; {of CASE statement}
END;  {DoMouseDown}
In Listing 5-9, when FindWindow reports a mouse-down event in the content region of a window containing controls, DoMouseDown calls another application-defined procedure, DoContentClick, and passes it the window pointer returned by the FindWindow function as well as the event record.

Listing 5-10 shows an application-defined procedure, DoContentClick, that uses this information to determine whether the mouse-down event occurred in a control.

Listing 5-10 Detecting mouse-down events in a pop-up menu and a button

PROCEDURE DoContentClick (window: WindowPtr; event: EventRecord);
VAR
   mouse:      Point;
   control:    ControlHandle;
   part:       Integer;
   windowType: Integer;
BEGIN
   windowType := MyGetWindowType(window);    {get window type}

   CASE windowType OF 

   kPlaySoundsModelessDialogBox:
      BEGIN
         SetPort(window);
         mouse := event.where;   {get the mouse location}
         GlobalToLocal(mouse);   {convert to local coordinates}
         part := FindControl(mouse, window, control);
         IF control = gSpeedPopUpControlHandle THEN
            {mouse-down in Modem Speed pop-up menu}
            DoPopUpMenu(mouse, control);
         CASE part OF
            inButton:   {mouse-down in Play button}
               DoPlayButton(mouse, control);
            inCheckBox: {mouse-down in checkbox}
               DoDrumRollCheckBox(mouse, control);
            OTHERWISE
            ;
         END;  {of CASE for control part codes}
      END;  {of kPlaySoundsModelessDialogBox case}
   {handle other window types, such as document windows, here}
   END; {of CASE for window types}
END; {of DoContentClick}
Figure 5-15 shows the Play Sounds window; DoContentClick uses the FindControl function to determine whether the mouse-down event occurred in the pop-up menu, the Play button, or the Add Drum Roll checkbox.

First, however, DoContentClick uses the event record to determine the cursor location, which is specified in global coordinates. Because the FindControl function expects the cursor location in coordinates local to the window, DoContentClick uses the QuickDraw procedure GlobalToLocal to convert the point stored in the where field of the event record to coordinates local to the current window. The GlobalToLocal procedure takes one parameter, a point in global coordinates--where the upper-left corner of the entire bit image is coordinate (0,0). See Inside Macintosh: Imaging for more information about the GlobalToLocal procedure.

Figure 5-15 Three controls in a window

When it calls FindControl, DoContentClick passes the cursor location in the window's local coordinates as well as the pointer returned earlier by the FindWindow function (shown in Listing 5-9 on page 5-29).

If the cursor is in a control, FindControl returns a handle to the control and a part code indicating the control part. Because the pop-up control definition function does
not define control parts, DoContentClick tests the control handle returned by FindControl against a pop-up menu's control handle that the application stores
in its own global variable. If these are handles to the same control, DoContentClick calls another application-defined routine, DoPopUpMenu.

After checking whether FindControl returns a control handle to a pop-up menu, DoContentClick uses the part code that FindControl returns to determine whether the cursor is in one of the other two controls. If FindControl returns the inButton constant, DoContentClick calls another application-defined routine, DoPlayButton. If FindControl returns the inCheckBox constant, DoContentClick calls another application-defined routine, DoDrumRollCheckBox.

As described in the next section, all three of these application-defined routines--DoPopUpMenu, DoPlayButton, and DoDrumRollCheckBox--in turn use the TrackControl function to follow and respond to the user's mouse movements in
the control reported by FindControl.

Tracking the Cursor in a Control

After using the FindControl function to determine that the user pressed the mouse button when the cursor was in a control, use the TrackControl function first to follow and respond to the user's mouse movements, and then to determine which control part contains the cursor when the user releases the mouse button.

Generally, you use TrackControl after using the FindControl function to determine that the mouse-down event occurred in a control. You pass to TrackControl the control handle returned by the FindControl function, and you also pass to TrackControl the same point you passed to FindControl (that is, a point in coordinates local to the window).

The TrackControl function follows the movements of the cursor in a control and provides visual feedback until the user releases the mouse button. The visual feedback given by TrackControl depends on the control part in which the mouse-down event occurred. When highlighting the control is appropriate--in a button, for example--TrackControl highlights the control part (and removes the highlighting when the user releases the mouse button). When the user presses the mouse button while the cursor is in an indicator (such as the scroll box of a scroll bar) and then moves the mouse, TrackControl responds by dragging a dotted outline of the indicator. Figure 5-8 on page 5-10 illustrates how TrackControl provides visual feedback.

You can also use an action procedure to undertake additional actions as long as the user holds down the mouse button. For example, if the user is working in a text document and holds down the mouse button while the cursor is in a scroll arrow, your action procedure should continuously scroll through the document one line (or some equivalent measure) at a time until the user releases the button or reaches the end of the document. You pass a pointer to this procedure to TrackControl. ("Scrolling in Response to Events in Scroll Arrows and Gray Areas" beginning on page 5-52 describes how to do this.)

The TrackControl function returns the control's part code if the user releases
the mouse button while the cursor is inside the control part, or 0 if the user releases the mouse button while the cursor is outside the control part. Unless TrackControl returns 0 as its function result, your application should then respond as appropriate to
a mouse-up event in that control part. When TrackControl returns 0 as its function result, your application should do nothing.

Listing 5-11 on the next page shows an application-defined procedure, DoPlayButton, that uses TrackControl to track mouse-down events in the Play button shown in Figure 5-15. The DoPlayButton routine passes, to TrackControl, the control handle returned by FindControl. The DoPlayButton routine also passes to TrackControl the same cursor location it passed to FindControl (that is, a point in local coordinates). Because buttons don't need an action procedure, NIL is passed as the final parameter
to TrackControl.

Listing 5-11 Using the TrackControl function with a button

PROCEDURE DoPlayButton (mouse: Point; control: ControlHandle);
BEGIN
   IF TrackControl(control, mouse, NIL) <> 0 THEN  {user clicks Play}
   BEGIN
      IF gPlayDrumRoll = TRUE THEN  {user clicked Play Drum Roll checkbox }
         DoPlayDrumRoll;            { so play a drum roll first}
      SysBeep(30);   {always play system alert sound when user clicks Play}
   END;
END;  
When the user presses the mouse button when the cursor is in the Play button, TrackControl inverts the Play button. If the user releases the mouse button after moving the cursor outside the control part, TrackControl stops inverting the
button and returns the value 0, in which case DoPlayButton does nothing.

If, however, the user releases the mouse button with the cursor in the Play button, TrackControl stops inverting the Play button and returns the value for the inButton constant. Then DoPlayButton calls the Sound Manager procedure SysBeep to play the system alert sound (which is described in the chapter "Dialog Manager" in this book). Before releasing the mouse button, the user can move the cursor away from the control part and then return to it, and TrackControl will still return the part code when the user releases the mouse button.

For buttons, checkboxes, radio buttons, and the scroll box in a scroll bar, your application typically passes NIL to TrackControl to use no action procedure. However, TrackControl still responds visually to mouse events in active controls. That is, when the user presses the mouse button with the cursor over a control whose action procedure is set to NIL, TrackControl changes the control's display appropriately until the user releases the mouse button.

For scroll arrows and for the gray areas of a scroll box, you need to define your own action procedures. You pass a pointer to the action procedure as one of the parameters to TrackControl, as described in "Scrolling in Response to Events in Scroll Arrows and Gray Areas" beginning on page 5-52.

For a pop-up menu, you must pass Pointer(-1) to TrackControl for its action procedure; this causes TrackControl to use the action procedure defined in the pop-up control definition function.

Listing 5-10 on page 5-30 calls an application-defined routine, DoPopUpMenu, when FindControl reports a mouse-down event in a pop-up menu. Listing 5-12 shows how DoPopUpMenu uses TrackControl to handle user interaction in the pop-up menu. By passing Pointer(-1) to TrackControl, DoPopUpMenu uses the action procedure defined in the pop-up control definition function.

Listing 5-12 Using TrackControl with a pop-up menu

PROCEDURE DoPopUpMenu (mouse: Point; control: ControlHandle);
VAR
   menuItem:   Integer;
   part:       Integer;
BEGIN
   part := TrackControl(control, mouse, Pointer(-1));
   menuItem := GetControlValue(control);
   IF menuItem <> gCurrentItem THEN
   BEGIN
      gCurrentItem := menuItem;
      SetMyCommunicationSpeed; {use speed stored in gCurrentItem}
   END;
END; {of DoPopUpMenu}
The action procedure for pop-up menus highlights the pop-up menu title, displays the pop-up menu, and handles all user interaction while the user drags up and down the menu. When the user releases the mouse button, the action procedure closes the pop-up box, draws the user's choice in the pop-up box (or restores the previous item if the user doesn't make a new choice), and removes the highlighting of the pop-up title. The pop-up control definition function then changes the value of the contrlValue field of the control record to the number of the menu item chosen by the user.

Because buttons do not retain settings, responding to them is very straightforward: when the user clicks a button, your application should immediately undertake the action described by the button's title. For pop-up menus and other types of controls, you must determine their current settings before responding to the user's action. For example, before responding, you need to know which item the user has chosen in a pop-up menu, whether a checkbox is checked, or how far the user has moved the scroll box. The action you take may, in turn, involve changing other control settings. Determining and changing control settings are described in the next section.

After learning how to determine and change control settings, see "Scrolling Through a Document" beginning on page 5-40 for a detailed discussion of how to respond to mouse events in scroll bars.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
11 JUL 1996