Click to See Complete Forum and Search --> : Validating a field in a Dialog


Kishore Kumar
May 27th, 1999, 04:33 AM
Hello ,
I am having a problem with validating a field.
Problem Description :
I am having a Simple Dialog With One Edit control ( Name ) and Ok and Cancel Buttons.Initially When the dialog is activated I am setting the focus to Name. On the Killfocus of Name I am Validating the name. If the validation is failed I am showing the message and again setting the focus to Name. My Problem is even the user presses the Cancel button , Killfocus of Name is called and focus is set to Name and dialog is not closed. Please help me. Code is void CTestDialog::OnKillfocusName( )
{
UpdateData( TRUE ) ;
if (ValidateName(m_strName) == FALSE)
{
AfxMessageBox("Enter a valid name.");
CWnd *ptrName = GetDlgItem(IDC_EDIT_NAME) ;
ptrName->SetFocus() ;
}
}




Please Help Me. Thanks.

Kishore Kumar D
Bangalore.
India.

Jörg Eckart
May 27th, 1999, 05:02 AM
Hi,

my suggestion is to override the method CDialog::OnOK which is called when the user clicks the OK button. Here you can validate the user input. If the input is not valid you can display the message box and set the focus on the edit control but don't call CDialog::OnOK. Only in case of a valid user input call CDialog::OnOK so the dialog will be closed.

Your idea with the kill focus event forces the user to enter a valid input before he can leave the edit control, so this method is not very practical.

Greetings, Jörg

Jason Teagle
May 27th, 1999, 05:36 AM
In terms of how you are handling the validation, I agree with Jörg's post; if you look at other dialogue boxes carefully, you will see that most check the data when you attempt to OK the page. If you select automatic validation of controls, such as when you assign a UINT member variable to an edit box and set the limits, you will find that you cannot cancel the dialogue box unless you put valid data in (or else the focus never goes back to the bad data, I can't remember which).

However, if you REALLY want the functionality you are trying to achieve, do the following:

1) Define a user message, and make sure you assign a message number that is not used by common controls (notification messages use WM_USER + n, where n is 1 - 10 or so). E.g.:

#define UM_VALIDATENAME (WM_USER + 100)

2) In the OnKillfocusName() function, instead of trying to validate right then, post (NOT send) a UM_VALIDATENAME message to the dialogue box, i.e.:

PostMessage(UM_VALIDATENAME);

This should be all that you do here, you should then let the system continue - no focus changing.

3) Add a handler for UM_VALIDATENAME, and in that you can then validate the data and change the focus back to the edit control.

The reason why this will work is to do with the order in which message are processed. With your code as it is, WM_SETFOCUS is sent to the Cancel button, then WM_KILLFOCUS to the edit box, which then triggers your code; your code changes the focus, which send WM_SETFOCUS to the edit box and then WM_KILLFOCUS to the Cancel button. Now, because the focus is no longer on the button, the WM_LBUTTONDOWN message which was waiting in the queue goes to the edit control instead of the button, so the click event is never generated.

By posting a user message instead of trying to validate straight away, if the user clicks the Cancel button the WM_SETFOCUS is sent to the button, then WM_KILLFOCUS to the edit control; this now adds UM_VALIDATENAME to the queue, which goes AFTER the WM_LBUTTONDOWN. So, the button is allowed to be pressed, the dialogue box closes and the UM_VALIDATENAME is ignored.

If the user just <TAB>s to the Cancel button, once the set and kill focus messages have been issued there are no more messages to process - so the UM_VALIDATENAME you posted now gets dealt with. So, the data is validated and the focus goes back to the box as required.

Does that help?