Important: The information in this document is obsolete and should not be used for new development.
Recipes--Dialog Boxes and Controls
This section provides a general outline of how to work with dialog boxes and controls, as well as recipes and sample code that demonstrate how to display a modal dialog box and respond to user manipulation of control objects.Working With Dialog Boxes and Controls--A General Outline
Dialog boxes are handled like other window and view objects in your application. Dialog boxes usually contain controls such as buttons, checkboxes, and scroll bars. MacApp defines theTControl
class, a subclass ofTView
, and a number of specialized control view subclasses.
- To initialize MacApp's UDialog unit, you call the
InitUDialog
routine from yourmain
routine, after callingInitUMacApp
and before creating your application object. (See "Recipe--Launching a Simple Application," beginning on page 292.)- To use a dialog box in your application, follow these steps:
- Define a subclass of
TDialogView
to serve as the main dialog-box view.- Use a view-editing program to define a window containing the main dialog-box view and its view hierarchy of control views and other view objects.
- In the resource definition, set the window's
fTargetID
field to the view ID of an edit-text or number-text view to be selected when the dialog box is first displayed. If there are no edit- or number-text views in the dialog box, setfTargetID
to the view ID of the dialog view.
- To work with control view objects in a dialog box, follow these steps (see also the recipe beginning on page 461):
- Define a subclass of each MacApp control view class that you need to modify.
- Override the
DoEvent
method of your control view class to handle specific events. Constants for the event numbers generated by user actions with control objects are defined in the UMacAppGlobals unit and are shown in Table 19-1.For a different approach to control view objects, see the recipe beginning on page 465.
- To use a modal dialog box (page 467), follow these steps:
- In your view resource template (described in step 2 above), identify which control items in the dialog box cause it to be dismissed.
- Create the window and view hierarchy for your dialog box from the view resource you have defined. Call the
NewTemplateWindow
method of MacApp's global view server object (gViewServer
) to create the window.- If you do not use the
TDialogView
class for your dialog-box view, make sure the view class you do use calls its window'sSetDialogItems
method to associate aTDialogBehavior
object (see page 239) with the window. (TheTDialogView
class callsSetDialogItems
automatically in itsDoPostCreate
method.)- Call the window's
PoseModally
method to display the dialog box. The window'sPoseModally
method calls thePoseModally
method of itsTDialogBehavior
object. The window'sPoseModally
method returns the ID of the control object that dismisses the dialog box. For example, the user may dismiss the dialog box by clicking the OK button, the Cancel button, or another button. Your application can base its action on the returned ID.- After
PoseModally
returns, call theClose
method of the window.
Recipe--Responding to User Actions in a Control View
When a user presses the mouse button while the cursor is over an application window, the application receives a mouse-down event from the operating system. The application object dispatches the event to the window containing the mouse-down event--typically, the event is passed down to the smallest subview that contains the event and wishes to respond to it. This type of event dispatching is described in "View Hierarchy Dispatching," beginning on page 103.MacApp's control view classes include views to display standard buttons, scroll bars, checkboxes, radio buttons, and text- and number-entry fields. All of these classes descend from the
TCtlMgr
class, and for many of them theTCtlMgr::DoMouseCommand
method handles a mouse-down event in the control view. TheDoMouseCommand
method calls the Toolbox routineTrackControl
to track the mouse while the user presses the mouse button. IfTrackControl
returns a nonzero value (the user clicked the control),DoMouseCommand
callsHandleEvent
, passing the control view'sfEventNumber
field. Possible values for thefEventNumber
field are shown in Table 19-1.The
HandleEvent
method is a method ofTEventHandler
. It gives any enabled behavior object a chance to handle the event in itsDoEvent
method. If none does, it calls the control view'sDoEvent
method. You can overrideDoEvent
in your control view subclasses to respond to a user click on the control.MacApp defines event number constants, as well as certain change notification constants, in the UMacAppGlobals unit. Both are shown in Table 19-1.
To override the
DoEvent
method of a control view class to respond to a user action, you perform these steps:
The sample code shown in this recipe is for a hypothetical button class.
- Define a subclass for the control view.
- The subclass should descend from the
TCtlMgr
class, or from one of MacApp's predefined control classes, such asTButton
orTCheckBox
.- Override the
DoEvent
method.
- Implement a
DoEvent
method.
- In the
DoEvent
method, respond to event numbers of interest.- For other event numbers, call
Inherited
.
Define a Subclass for the Control View
The following is a partial listing for a custom button class:
class TYourSpecialButton : public TButton { MA_DECLARE_CLASS; public: virtual void DoEvent(EventNumber eventNumber, TEventHandler*source, TEvent* event); // Some code not shown. }You define additional fields and methods to perform the operations specific to the TYourSpecialButton class.Implement a DoEvent Method
TheDoEvent
method is called when a user clicks an instance of your control class--in this case, a special button view. TheDoEvent
method responds to event numbers of interest and callsInherited
for event numbers it does not handle.
void TYourSpecialButton::DoEvent(EventNumbereventNumber, TEventHandler*source, TEvent* event) // Override. { switch (eventNumber) { case mButtonHit: // Perform any special handling for your // button class here. break; default: // Event not handled; pass it on. Inherited::DoEvent(eventNumber, source, event); break; } }This simple version ofDoEvent
performs special handling for an mButtonHit event number. Otherwise, it callsInherited
to let its parent class handle the event.Recipe--An Alternative Approach to User Actions in
The previous recipe described how to handle a user action by defining a subclass of
a ControlTButton
and overriding theDoEvent
method. Although that mechanism is effective and works for buttons and other controls, it does have some drawbacks:
On the other hand, you nearly always define a subclass of
- Your button class may require knowledge of other things that take place in its dialog box.
- You may have to define many subclasses of
TButton
, even though each class has a very limited function.
TDialogView
(see page 460), and the dialog view class is a logical place to centralize knowledge about events that take place in the dialog. Why not use theTDialogView
class to handle user actions for simple control items?To handle events (in this case, a button hit) in your subclass of
TDialogView
, you perform these steps:
The sample code in this recipe is for a hypothetical dialog view.
- Define a unique constant for each event you will handle.
- Define a view resource for your dialog view.
- Use the
TButton
class for a button used in the dialog box.- Set the event number field of the button to the constant you defined.
- Override the
DoEvent
method in your subclass ofTDialogView
.
- Your
DoEvent
method should handle all the event constants you have defined.
Define a Unique Constant for Each Event You Will Handle
To identify a button event you are interested in, you use code like the following:
const EventNumber mCountRaisinsButtonHit = 14001;The constant number, in this case 14001, should be well outside the range of event numbers defined by MacApp (shown in Figure 19-1). Also, make sure that any event number constants you define remain unique across all code modules in your application.Define a View Resource for Your Dialog View
The use of view dialog resources is described in "Working With View Resource Templates," beginning on page 425. Using a view resource editor application, you can create view hierarchies in a graphical environment. A view editor also allows you to set initial values for many fields of the view objects in the hierarchy.Use a view editor to create a
TButton
object for the Count Raisins button, then set the button'sfEventNumber
field to 14001.
- IMPORTANT
- Be sure the number you enter (14001) matches the constant defined in the previous step.
Override the DoEvent Method in Your Subclass of TDialogView
You normally define a subclass ofTDialogView
to serve as the main dialog view for dialog boxes in your application. You can define your subclass with code like the following, which overrides the DoEvent method:
class TYourDialogView : public TDialogView { MA_DECLARE_CLASS; public: virtual void DoEvent(EventNumber eventNumber, TEventHandler*source, TEvent* event); // Override. . . . }Your version of the DoEvent method should handle any control event constants you have defined, using code like the following:
void TYourDialogView::DoEvent(EventNumbereventNumber, TEventHandler*source, TEvent* event) // Override. { switch (eventNumber) { case mCountRaisinsButtonHit: long raisinsPerBox = this->CountTheRaisins() this->SetRaisinCount(raisinsPerBox); // Any other code to handle this case. break; // Add cases for other event numbers your dialog view handles. // Default is to pass the event on. default: // Event not handled; pass it on. Inherited::DoEvent(eventNumber, source, event); break; } }In this case, when the Count Raisins button is hit, the dialog view determines how many raisins are in the box and sets the appropriate variable. It may need to access other fields of the dialog box, which it can rightly be expected to know about.You can use this mechanism to handle many control events for a given dialog box, though at some point the switch statement may become too large for good coding style.
Recipe--Displaying a Modal Dialog Box
The DemoDialogs application has a Modal Beep Dialog menu command. The menu command displays a modal dialog box containing OK and Cancel buttons, a static text item, and a number text item in which the user can enter the number of beeps. The default number of beeps is 1, the minimum is 1, and the maximum is 10. These values are specified in the fileDemoDialogs.r
, in thecModelessBeepDialog
view resource, in theNumberText
subview definition, by the text "1, 1, 10" (shown on page 470). You can modify these values by editing the view resource.If the user dismisses the dialog box with the OK button, the specified number of beeps is performed, unless it is out of range--then an error message is displayed and the dialog box is not dismissed. If the user cancels the dialog box, no beeps are performed. The Modal Beep Dialog menu command demonstrates how to display a modal dialog box.
To display a modal dialog box, you perform these steps:
The sample code shown in this recipe is from the DemoDialogs application.
- Define a
'View'
resource for the dialog box window and view hierarchy.
- Define a resource ID constant for the view resource.
- Define the view resource for the window.
- Create, display, and close the dialog box.
- Create the window with the
NewTemplateWindow
method.- Call the window's
PoseModally
method to display the dialog box.- Call the window's
Close
method after the user dismisses the dialog box.
Define a 'View' Resource for the Dialog-Box Window Hierarchy
The recipe beginning on page 451 ("Recipe--Creating a Window From a View Resource") describes how to define a resource ID constant and a view resource for a window. The key to defining a view resource for a dialog box is to use aTDialogView
as the parent view for any control view objects in the dialog box.The DemoDialogs application defines a constant for the Modal Beep Dialog menu command in the file
DemoDialogs.r
:
#define cModalBeepDialog1005The following is a partial listing of the'View'
resource for the dialog box displayed by the Modal Beep Dialog menu command. It is defined in the fileDemoDialogs.r
:
resource 'View' (cModalBeepDialog, purgeable) {MAThreeOh, { ViewSignatureAndClassname {'wind', 857, "", 'WIND', enabled, noIdle, {}, MAThreeOh, {72, 64}, {80, 270}, sizeVariable, sizeVariable, shown, . . . Window {movableDBoxProc, 'numb', goAwayBox, notResizable, ignoreFirstClick, freeOnClosing, disposeOnFree, closesDocument, openWithDocument,dontAdaptToScreen, dontStagger, forceOnScreen, centerHorizontally, doesntFloat, doesntHideOnSuspend, generateActivates, 0, kWindowTitles, 6}, 1}, ViewSignatureAndClassname {'dlog', 666, "", 'DLOG', enabled, noIdle, {}, MAThreeOh, {0, 0}, {1000, 500}, sizeFixed, sizeFixed, shown, doesntWantToBeTarget, handlesCursor, letsSubViewsHandleCursor, noCursorID, handlesHelp, letsSubViewsHandleHelp, noHelpID, 1, NoDrawingEnvironment {}, NoAdorners {}, 0, DialogView {'ok ', 'cncl'}, 4}, ViewSignatureAndClassname {'butn', 208, "", 'ok ', enabled, noIdle, {}, MAThreeOh, . . . ViewSignatureAndClassname {'butn', 92, "", 'cncl', enabled, noIdle, {}, MAThreeOh, . . . ViewSignatureAndClassname {'stat', 96, "", noID, notEnabled, noIdle, {}, MAThreeOh, . . . ViewSignatureAndClassname {'nmbr', 176, "", 'numb', enabled, noIdle, . . . NumberText {mEditTextHit, notHilited, notDimmed, sizeable, {3, 3, 3, 3}, 130, dontPreferOutline, dontAutoWrap, dontEraseFirst, justRight, kStaticTextText, 19, 5, LeftRightUpDownBackspace, 1, 1, 10},NoSubviews} } };This view resource defines a window containing a dialog view, Cancel and OK buttons, a static text view, and a number text view. Note that the view ID for the number text view is'numb'
.Create, Display, and Close the Dialog Box
The DemoDialogs application creates, displays, and closes the Modal Beep Dialog dialog box in the MakeModalBeepDialog method:
void TTestApplication::MakeModalBeepDialog(CommandNumber aCommandNumber) { TWindow * aWindow = NULL; IDType dismisser; TNumberText * aNumberText = NULL; long n = 0; // Create the dialog box window. Fail if unsuccessful. aWindow = gViewServer->NewTemplateWindow( (short)aCommandNumber, NULL); FailNIL(aWindow); // Display the dialog box as a modal dialog. dismisser = aWindow->PoseModally(); // On return, examine dismisser. if (dismisser == 'ok ') { // Find the number text view and extract the number of beeps. // Use dynamic cast to make sure we have the right kind of view. aNumberText = MA_DYNAMIC_CAST(TNumberText, aWindow->FindSubView('numb')); if (aNumberText) n = aNumberText->GetValue(); } aWindow->CloseAndFree(); for (long i = 1; i <= n; i++) gApplication->Beep(2); } // TTestApplication::MakeModalBeepDialogValidation occurs when the user attempts to dismiss the dialog box with the OK button. Validation is described in "Validating Dialog-Box Data," beginning on page 244. In your application, you can replace the code that creates beeps with code that uses the entered number for some other purpose.Call the Window's PoseModally Method to Display the Dialog Box
The following line from the MakeModalBeepDialog method displays the modal dialog box:
dismisser = aWindow->PoseModally();TheTWindow::PoseModally
method calls the PoseModally method of itsTDialogBehavior
behavior object. That method repeatedly makes the call
gApplication->PollEvent(kAllowApplicationToSleep);
until the dialog box is dismissed. It then returns the ID of the control object that dismissed the dialog box (such as the Cancel or OK button).
Call the Window's Close Method
The following line from the MakeModalBeepDialog method closes the modal dialog box window:
aWindow->CloseAndFree();TheCloseAndFree
method callsClose
to close the window. If the window is freed on closing,CloseAndFree
also frees it.
- Note
- Your application can validate data when the user attempts to close the dialog box. If the data is invalid, you can put up an error message and leave the dialog box open. For more information, see "Validating Data When a User Accepts Changes to a Dialog Box," beginning on page 244.