>I think that I was wrong about being able to set an event handler for the
>FrmDoDialog (spelled incorrectly in my original posting)
>
>Does anybody know for sure whether this can be done - or better yet - why
>would you want to do it this way??
Sure, this is fine to do. The benefit is that you get more control over
the events, and can handle things that FrmDoDialog doesn't know about, e.g.
scrolling your data. It often is better once you're at this stage to not
use FrmDoDialog, since that routine is really written for the simple
(common) case... doing the stuff yourself is only a little more work and is
more flexible.
Here's some recipe-style sample code which is somewhat "raw" and not yet
posted - I wrote it and nobody else has yet reviewed it or made
suggestions, but perhaps it would help clarify the possibilities for you.
(Feedback is very welcome - if you send it directly to me that'd be
easiest.)
-David Fedor
Palm, Inc.
(the formatting lost a little something when converted from html to text,
but all the content is still there.)
Modal Dialogs
Modal dialogs are for uses such as "Details" dialogs, as well as Alarms,
and occasionally are used for more complex Alerts. Simple alerts are easier
to implement with FrmAlert, but could be created this way as well.
There are two different ways to implement modal dialogs: by using
FrmDoDialog() or by writing the event handler yourself. The process of
creating the resources is the same for both.
To create a "Details" dialog in Constructor:
1. Create a new Form object and name it "Details". (Forms and Dialogs
are really the same thing except in concept and usage patterns.)
2. Set the left origin to 2, and the width to 156. That will be
full-width and leave just enough room for the two-pixel border which is
drawn outside the form bounds.
3. Set the top origin and the height such that their sum equals 158,
so that it will be at the very bottom of the window. For this example, use
a top origin of 98 and a height of 60.
4. Turn on "Usable", "Modal", and "Save Behind".
5. If appropriate, create a Help resource for this dialog by setting a
Help ID (by convention this is equal to the form's ID) and clicking the
"Create" button. The text you enter will automatically be displayed when
the user taps the "i" button in the dialog.
6. Set the form's title to "Details".
7. Add the "OK" and "Cancel" buttons. The "OK" button should have its
left coordinate 5, top 43, width 36 and height 12. The "Cancel" button
should have its left coordinate 47 and all other coordinates the same as
the "OK" button. These coordinates are the standard placement of buttons
and result in the standard 4 pixel border between the buttons and the
dialog's left and bottom edges. If you make the dialog taller or shorter,
keep the same distance from the buttons to the bottom edge by adding the
top coordinate to the height and verifying that the result is 5 less than
the height of the dialog. (5 instead of 4 because the button's border is
drawn outside of its bounds.)
8. Set the labels and object identifiers for the buttons to "OK" and
"Cancel".
9. The form's "Default Button ID" should now be set, typically to the
"OK" button's ID, except in cases where this dialog is the kind which is
confirming deletion of data. If the user switches to another application
while this dialog is active, the system will simulate a press of the
default button ID, so you should choose the appropriate default action:
usually "OK" or "Done".
10. You can now add the other controls which you need on this dialog.
11. Also add the "Details" button to the main form, which the user will
tap to go to this dialog.
Now that you have the resources created, you need to decide which of three
ways you want to use to implement the code for the dialog. From easiest to
most complex, but therefore from least to most control, the options are as
follows: you can use FrmDoDialog() without an event handler, or
FrmDoDialog() with a "partial" event handler, or you could use your
application's normal event loop and a "full" event handler.
The primary drawback to using FrmDoDialog() is that you have slightly less
control over the event handling, since FrmDoDialog() runs its own event
loop instead of yours. Thus if you are doing communications or are using
event timeouts for some background processing or updating, FrmDoDialog()
would not be a good choice. The benefit of FrmDoDialog() is that you need
to write less code and it is located in only one place in your application.
Option A: FrmDoDialog()
If you choose to use the simplest case, FrmDoDialog() without an event
handler, then add code as follows to the event handler of the form which is
opening the details dialog. Ours is opened from a "Details" button on the
main form:
if (eventP->data.ctlSelect.controlID == MainDetailsButton) {
frmP = FrmInitForm(DetailsForm);
/* initialize your controls on the form here */
// open the dialog, and wait until a button is pressed to close it.
whichButton = FrmDoDialog(frmP);
if (whichButton == DetailsOKButton) {
/* get data from controls on the form to save/apply changes */
}
FrmDeleteForm(frmP);
handled=true;
}
You now have a functioning details dialog. All that remains is to
initialize the controls upon it right before calling FrmDoDialog() and to
save or apply the changes, right after calling FrmDoDialog(), where the
comments indicate.
Option B: FrmDoDialog() with an event handler
If you want more control over the event processing, you can still use
FrmDoDialog() in conjunction with a "partial" event handler. This handler
will let you take care of your special events, but still relies on
FrmDoDialog() to do most of the work since it will handle any event that
the handler didn't. With this method, use the same code as the previous
FrmDoDialog() example, but insert one line before calling FrmDoDialog():
FrmSetEventHandler(frmP, DetailsPartialEventHandler);
DetailsPartialEventHandler() will be called by FrmDoDialog(), to give it a
chance to process each event before FrmDoDialog() does. The code for
DetailsPartialEventHandler() could be as follows, if you had a routine to
validate the data entered on the details dialog:
static Boolean DetailsPartialEventHandler(EventPtr eventP)
{
Boolean handled = false;
if ((eventP->eType == ctlSelectEvent) &&
(eventP->data.ctlSelect.controlID == DetailsOKButton)) {
if (ValidationFailsOnTheInput()) {
FrmAlert(PleaseFixYourInputAlert);
// tell FrmDoDialog we handled this event, so it shouldn't do
anything
handled=true;
}
}
return handled;
}
Option C: Using the application's event loop and a full event handler
For maximal control over the entire event handling of the dialog, you can
treat this dialog just like a normal form in your application. Create its
event handler function as follows. Note that when the dialog is done, it
uses FrmReturnToForm(0) to close itself and go back to the previously
active form. Therefore the code to save the data is in the dialog's event
handler, instead of in the code of whoever brought up the dialog (which in
this example was the Details button of the main form).
static Boolean DetailsHandleEvent(EventPtr eventP)
{
Boolean handled = false;
FormPtr frmP;
switch (eventP->eType) {
case frmOpenEvent:
frmP = FrmGetActiveForm();
/* initialize UI objects here */
FrmDrawForm(frmP);
handled = true;
break;
case ctlSelectEvent:
if (eventP->data.ctlSelect.controlID == DetailsOKButton) {
/* save or apply the changes now */
FrmReturnToForm(0);
handled = true;
break;
}
else if (eventP->data.ctlSelect.controlID == DetailsCancelButton) {
/* don't save changes, just return. */
FrmReturnToForm(0);
handled = true;
break;
}
default:
break;
}
return handled;
}
You also need to specify the event handler for the form, in your
AppHandleEvent routine:
case DetailsForm:
FrmSetEventHandler(frmP, DetailsHandleEvent);
break;
And now to bring up this dialog, your button handler uses FrmPopupForm
instead of FrmDoDialog. The form is loaded by your AppHandleEvent routine,
and deleted when DetailsHandleEvent calls FrmReturnToForm.
if (eventP->data.ctlSelect.controlID == MainDetailsButton) {
MenuEraseStatus(0); // in case the status is still active
// Some apps might want to save the current focus here.
FrmPopupForm(DetailsForm);
handled=true;
}
--
For information on using the Palm Developer Forums, or to unsubscribe, please see
http://www.palmos.com/dev/tech/support/forums/