[comp.windows.ms.programmer] Controlling the input focus

sdollins@yoyodyne.ncsa.uiuc.edu (Steven Dollins) (06/17/91)

Hi, all.
    The program I'm working on has a dialog box that contains an edit
field.  The edit field should only accept integers in a specified range.
If the user enters a non-integer or an integer out of the specified
range and then attempts to leave the edit control, the program pops up
an error message box.
    When the user rids himself of the error message, I would like the
input focus to return to the edit control, forcing the user to enter a
valid number.  Here's what I have so far:

    case IDSLICE_INDEX:     /* ID for the edit field. */
        if (HIWORD(lParam)==EN_KILLFOCUS) {
            iIndex = GetDlgItemInt(hwnd, IDSLICE_INDEX, &bErr, FALSE);
            if (!bErr || (iIndex>iMaxIndex)) {
                wsprintf(TextBuf,
                    "The index must be between 1 and %d.", iMaxIndex);
                ErrMsg(TextBuf);
                return FALSE;
            }
        }
        break;

    Is there any simple way to put the input focus back if the user
tries to TAB to another field or, in the worst case, tries to hit OK?
The user should, on the other hand, have the option to "Cancel".

    Suggestions anyone?

                                        - Steven Dollins
                                          sdollins@ncsa.uiuc.edu

    "We have no theology.  We have no philosophy.  We dance."

bonneau@hyper.hyper.com (Paul Bonneau) (06/18/91)

In article <1991Jun17.005532.4543@ux1.cso.uiuc.edu> sdollins@yoyodyne.ncsa.uiuc.edu (Steven Dollins) writes:
>Hi, all.
>    The program I'm working on has a dialog box that contains an edit
>field.  The edit field should only accept integers in a specified range.
>If the user enters a non-integer or an integer out of the specified
>range and then attempts to leave the edit control, the program pops up
>an error message box.
>    When the user rids himself of the error message, I would like the
>input focus to return to the edit control, forcing the user to enter a
>valid number.  Here's what I have so far:
>
>    case IDSLICE_INDEX:     /* ID for the edit field. */
>        if (HIWORD(lParam)==EN_KILLFOCUS) {
>            iIndex = GetDlgItemInt(hwnd, IDSLICE_INDEX, &bErr, FALSE);
>            if (!bErr || (iIndex>iMaxIndex)) {
>                wsprintf(TextBuf,
>                    "The index must be between 1 and %d.", iMaxIndex);
>                ErrMsg(TextBuf);
>                return FALSE;
>            }
>        }
>        break;
>
>    Is there any simple way to put the input focus back if the user
>tries to TAB to another field or, in the worst case, tries to hit OK?
>The user should, on the other hand, have the option to "Cancel".
>
At first glance, one might be tempted to simply call
SetFocus() at the end of the above code fragment.
Unfortunately, this won't work.  The reason is that the
EN_KILLFOCUS is being sent in response to a WM_KILLFOCUS
which is sent by the SetFocus() routine.  But SetFocus()
is yet to send a WM_SETFOCUS.  So the problem is, you
get the following sequence of events (assuming a tab):

	edit gets WM_KILLFOCUS
	app call SetFocus()
	tabbed-to control gets WM_KILLFOCUS
	edit gets WM_SETFOCUS
	edit gets WM_SETFOCUS

What has happened is that a control which never had the focus,
(the control the user tried to tab to) received a WM_KILLFOCUS.
This can have the undesirable effect (depending on the control)
that the cart is inverted, making a caret to appear in the
tabbed-to control.

So, an alternative is post a private message to yourself,
upon receipt of which you set the focus back to the edit.
Posting the message removes the recursion.  However, you
have to make sure that other wierd effects don't occur
due to processing the messages that were already in the
queue before the post (usually not too difficult).

cheers - Paul Bonneau.