Doing nothing and not closing the dialog box when the user presses OK is not a good interface. You expect a dialog box to go away when you press OK don't you?
A user interface like this makes for an unexpected behavior. Besides, if we put ourselves in the user's shoes, how can h 848f54i e/she find out what is wrong? The software doesn't explain anything, doesn't tell the user what to do to correct the situation, it just silently ignores the input. This is the worst behavior we could imagine.
Well, there are two solutions for this. We can disable the OK button so that this problem doesn't appear at all, or we could put up a message using our MessageBox API informing the user that a text must be entered.
Let's see how we would implement the first solution.
To be really clear, the OK button should start disabled, but become active immediately after the user has typed some text. If, during editing, the user erases all text that has been entered, the OK button should revert to its inactive state.
We can do this by processing the messages that our edit field sends to us. Edit fields are very sophisticated controls, actually a full-blown mini-editor in a small window. Each time the user types anything in it, the edit field procedure sends us a WM_COMMAND message, informing us of each event.
We change our dialog procedure as follows:
case WM_COMMAND:
switch (LOWORD(wParam))
else
EnableWindow(
GetDlgItem(hwndDlg,IDOK),
0);
break;
}
break;
}
break;
We add a new case for this message. But we see immediately that this nested switch statements are getting out of hand. We have to split this into a function that will handle this message. We change again our dialog box procedure as follows:
case IDCANCEL:
EndDialog(hwndDlg,0);
return 1;
case IDENTRYFIELD:
return
EntryFieldMessages(hwndDlg,wParam);
This is much clearer. We put the code for handling the entry field messages in its own procedure, "EntryFieldMessages". Its code is:
int EntryFieldMessages(HWND hDlg,WPARAM wParam)
else // no text, disable the IDOK button
EnableWindow(hIdOk,0);
break;
}
return 1;
Let's look at this more in detail. Our switch statement uses the HIWORD of the first message parameter. This message carries different information in the upper 16 bits (the HIWORD) than in the lower 16 bits (LOWORD). In the lower part of wParam we find the ID of the control that sent the message, in this case IDENTRYFIELD, and in the higher 16 bits we find which sub-message of WM_COMMAND the control is sending to us, in this case EN_CHANGE , i.e. a change in the text of the edit field.
There are many other notifications this small window is sending to us. When the user leaves the edit field and sets the focus with the mouse somewhere else we are notified, etc. But all of those notifications follow the same pattern: they are sub-messages of WM_COMMAND, and their code is sent in the upper 16 bits of the wParam message parameter.
Continuing the analysis of EntryFieldMessages, we just use our friend GetDlgItemText to get the length of the text in the edit field. If there is some text, we enable the IDOK button with the API EnableWindow. If there is NO text we disable the IDOK button with the same API. Since we are getting those notifications each time the user types a character, the reaction of our IDOK button will be immediate.
But we have still one more thing to do, before we get this working. We have to modify our InitializeApp procedure to start the dialog box with IDOK disabled, since at the start there is no text in the entry field.
static int InitializeApp(HWND hDlg,WPARAM wParam, LPARAM lParam)
We recompile, and it works. The OK button starts disabled (grayed), and when we type the first character it becomes active, just as we wanted. When we select all the text in the entry field, and then erase it, we observe that the button reverts to the inactive state.
|