Jun 98 Getting Started
Volume Number: 14
Issue Number: 6
Column Tag: Getting Started
Modal Dialog Filter
by Dave Mark
Filtering Events in a Modal Dialog
DLOGFilter shows you how to write a filter procedure for a modal dialog. As usual,
we'll create and run the project here. You can type it all in, start with last month's
column and make changes, or just get the project files from
ftp://ftp.mactech.com/src/.
Creating the DLOGFilter Resources
Create a folder named DLOGFilter in your Development folder. Next, jump into ResEdit
and create a new file named DLOGFilter.rsrc inside the DLOGFilter folder.
Create an MBAR resource using the specifications in Figure 1. Be sure that the
MBAR's resource ID is set to 128.
Figure 1. Specifications for the MBAR resource.
Next, create three MENU resources using the specifications in Figure 2 as a guide. Be
sure to include a separator line as the second item in all three MENUs. Remember to
type in the appropriate command key equivalents (two for the File menu and four for
the Edit menu).
Figure 2. Specifications for the three MENU resources.
Next, create a DLOG resource according to the specifications in Figure 3. Be sure that
the modal dialog window icon (8th from the left) is selected, that the DITL ID is set to
128 and the "Initially visible" and "Close box" check boxes are unchecked, and that the
Top, Left, Height, and Width fields are filled in as noted. Remember, if your DLOG
editor uses Bottom and Right instead of Height and Width, select Show Height & Width
from the DLOG menu.
Figure 3. Specifications for the DLOG resource.
Next, select Auto Position from the DLOG menu. When the Auto Position dialog
appears, use the pop-up menus to direct Mac OS to automatically center our dialog on
the main screen.
Figure 4. Proper settings for our DLOG's auto-position dialog.
Next, double-click the blank dialog box in the middle of the DLOG editing window to
create a new DITL resource with an id of 128. The DITL contains six items. Create an
OK button (Figure 5) and then a Cancel button (Figure 6).
Figure 5. Specifications for the OK button.
Figure 6. Specifications for the Cancel button.
Next, create a static text label (Figure 7) and its corresponding edit text field
(Figure 8). Our dialog filter procedure will limit the number of characters entered
in this field to 10.
Figure 7. Specifications for the first static text item.
Figure 8. Specifications for the first edit text field.
Now create a second static text label (Figure 9) and its corresponding edit text field
(Figure 10). Our dialog filter procedure will only allow the digits 0 through 9 to be
typed in this field. When the OK button is clicked, our main program will check to be
sure the number typed was between 1 and 100.
Figure 9. Specifications for the second static text item.
Figure 10. Specifications for the second edit text field.
Figure 11 shows the DITL resource with all six items in place. Notice that the OK
button is in the lower right corner with the Cancel button immediately to its left. This
attention to detail is what makes the Mac so easy to use.
Figure 11. A look at the completed DITL resource.
Now create an ALRT resource using the specifications shown in Figure 12. This alert
will be used to display various messages of interest to the user. Make sure that the
DITL ID is set to 129. Then, change the ALRT's resource ID to 129. (Select Get
Resource Info from the Resource menu.) See Figure 12.
Figure 12. Specifications for the ALRT resource.
Next, double-click the ALRT box in the middle of the ALRT editing window to create a
new DITL resource. The ALRT DITL should have a resource id of 129 and will consist of
2 items. The OK button, used to dismiss the alert, is detailed in Figure 13.
Figure 13. Specifications for the alert's OK button.
The second DITL item is a static text item (Figure 14). Notice that the text provided
reads: ^0. The Dialog Manager allows you to provide up to four strings (^0, ^1, ^2, and
^3) which may appear in any item in any DITL in your program. The function
ParamText() allows you to substitute values for any of these strings. We'll use
ParamText() to specify the message displayed by this alert.
Figure 14. Specifications for the static text item.
Figure 15 shows the message alert's DITL once we're done creating the two DITL
items.
Figure 15. The message alert's DITL in final form.
Creating the DLOGFilter Project
Quit ResEdit, being sure to save your changes. Launch CodeWarrior and create a new
project based on the Mac OS:C/C++:Basic Toolbox 68k stationary. Turn off the Create
Folder check box. Name the project DLOGFilter.mcp and place it in your DLOGFilter
folder. Remove SillyBalls.c and SillyBalls.rsrc from the project; we will not be using
these files. From the Finder, drag and drop your DLOGFilter.rsrc file into the project
window. You also can remove the ANSI Libraries group from the project, because we
won't need them, either.
Select New from the File menu to create a new window. Save it with the name
DLOGFilter.c in your DLOGFilter folder. Select Add Window from the Project menu to
add DLOGFilter.c to the project. Your project window should look something like
Figure 16.
Figure 16. DLOGFilter project window.
You may have noticed that our aapplication every month has been named "Mac OS
Toolbox DEBUG 68K." This is name automatically provided by the project stationary.
You can change this name in the Project Settings Target panel. Open your project
settings by clicking the settings button in the Project window (Figure 16) just to
the right of the of the target popup. (The popup says "68K Debug Mac OS Toolbox.") In
the project settings window, select the 68K Target panel as shown in Figure 17.
Enter "DLOGFilter app" in the File Name field. Close the window, clicking Save when
you are asked to save and clicking OK if you are warned about relinking the project.
Now your project wil build the application using this name.
Figure 17. DLOGFilter project window.
Walking Through the Source Code
DLOGFilter starts off #including necessary header files, then it begins a series of
#defines. You'll see these again as they are used throughout the code.
I know this is obvious, but here's a word or two about the naming convention I use in
my code. Start all constants with a lower-case k, with two exceptions. Menu and dialog
items start with a lower-case i and menu resource id's start with a lower case m.
Notice that the remainder of the constant name is spelled according to Pascal rules, as
opposed to C rules. Pascal starts each word with an upper-case letter, while C
traditionally uses all upper-case letters, separating each word by an underscore (_).
I think the Pascal method is much easier to read. As it happens, most of Apple's C code
uses the Pascal conventions as well.
#include
#include
#include
#include
#define kDialogResID 128
#define kMBARid 128
#define kMessageAlertID 129
#define kSleep 60L
#define kMoveToFront (WindowPtr)-1L
#define kNULLFilterProc NULL
#define kOn 1
#define kOff 0
#define kEditItemExists true
#define kEventNotHandledYet false
#define kEventHandled true
#define kMaxFieldLength 10
#define kEnterKey 3
#define kBackSpaceKey 8
#define kTabKey 9
#define kReturnKey 13
#define kEscapeKey 27
#define kLeftArrow 28
#define kRightArrow 29
#define kUpArrow 30
#define kDownArrow 31
#define kPeriodKey 46
#define kDeleteKey 127
#define iTenCharMaxText 4
#define iNumberText 6
#define mApple 128
#define iAbout 1
#define mFile 129
#define iDialog 1
#define iQuit 3
As usual, we've declared the global gDone as a Boolean to tell us when to drop out of the
main event loop. As always, we start global variables with the letter g. There are lots
of other naming conventions for variables. For example, some folks start their
variables with a letter indicating the type of the variable. This can come in handy if
you are writing code that gets shared among a group of people.
/************************************* Globals */
Boolean gDone;
Here's the function prototypes for every single routine in the program. Get in the
habit of providing function prototypes for all your routines. Since C++ requires
function prototypes, this is a good habit to get into.
/************************************* Functions */
void ToolboxInit( void );
void MenuBarInit( void );
void EventLoop( void );
void DoEvent( EventRecord *eventPtr );
void HandleMouseDown( EventRecord *eventPtr );
void HandleMenuChoice( long menuChoice );
void HandleAppleChoice( short item );
void HandleFileChoice( short item );
void DoDialog( void );
Here's an unusual prototype. Look at the return type for the function DLOGFilter().
pascal Boolean DLOGFilter( DialogPtr dialog, EventRecord
*eventPtr, short *itemHitPtr );
The pascal keyword tells the compiler that this routine should be called using Pascal,
as opposed to C, calling conventions. Here's why this is important. When your code
calls a regular C function, the compiler has no trouble using the C function-calling
conventions. When you call a Toolbox function, the rules change a bit. Since the
Toolbox was originally written in Pascal, all calls to it are made using the Pascal
calling conventions. When you call a Toolbox function from your code, the compiler is
smart enough to use the Pascal convention to pass parameters and return the return
value to your code. The compiler knows to do this because the Toolbox function
prototypes use the pascal keyword.
Where things get tricky is when you write a function in C that you'd like to be called
by a Toolbox function. For example, in this program, we're creating a function that
will be called, periodically by ModalDialog(). Which conventions do we use, C or
Pascal? As it turns out, we yield to the Toolbox and declare our function using the
pascal keyword. It's not important to understand the difference between C and Pascal
calling conventions just as long as you remember this rule: If your routine is designed
to be called by the Toolbox, be sure to declare it using the pascal keyword. Here's the
rest of the function prototypes.
Boolean ScrapIsOnlyDigits( void );
Boolean CallFilterProc( DialogPtr dialog,
EventRecord *eventPtr, short *itemHitPtr );
short CurEditField( DialogPtr dialog );
short SelectionLength( DialogPtr dialog );
void Message( Str255 messageStr );
main() initializes the Toolbox and menu bar, then enters the main event loop.
/************************************* main */
void main( void )
{
ToolboxInit();
MenuBarInit();

EventLoop();
}
Notice the new spelling of ToolboxInit(). (I used to spell it ToolBoxInit() -- Aack!)