[help]SetActiveWindow
hIeU nGuYeN -- nguyenh@rohan.sdsu.edu Thursday, February 22, 1996 hi all, i'm dong a modeless dlg on VC4.0. on my dlg there is a edit control field, i want to check each time the edit is killed focus. so i add OnKillFocus method for the edit control field in this method i call UpdateData( TRUE ) to update dlg's member variable. But now if the value of the edit control is invalid (out of range), and i clicked somewhere out of my dialog. the OnKillFocus is called and UpdateData is called a message window pop up warn user to reenter value. After click on OK to Accept the message, i couldn't go to my dlg again, and the message just keep pop up and doesn't go to my dlg to fix the error. I used SetActiveWindow(), SetFocus, none of them is working for me. Does anyone have any sugestion? Thank you in advance!
Mike Blaszczak -- mikeblas@msn.com Sunday, February 25, 1996 [Mini-digest: 2 responses] All of the behaviour you've described is "By design". That is, it's the way that Windows is designed to work. WM_KILLFOCUS is sent when a control loses focus--it's sent wether the user tabs out of the control, the control has focus and is losing it because the control is being destroyed, or another window (such as a message box) in the same application has come up. You should maintain some state flags in your CDialog member data. In DoDataExchange, you should check this flag and react appropriately if your kill focus handler is being handled. If you write DoDataExchange() to not pop up an error when you're handling WM_KILLFOCUS, you'll avoid the endless loop you're entering. As it stands, your code is responding to WM_KILLFOCUS by killing focus... and that just doesn't make sense. Forcing the focus someplace else is _NOT_ the answer because that'll just make more kill focus messages for your control, or make other windows not work they way they're designed to work. .B ekiM TCHAR sz[] = _T("So, I come home to watch Cops, but figure skating is on instead!"); -----From: daveferg@niagara.com This is an often repeated question. The general approach to validation is to post a use message from OnKillFocus. This allows resolution of the SetFocus/KillFocus before entering into another SetFocus/KillFocus. There is an article on this subject on MSDN and I believe it is mentioned in some MFC FAQ. Although the above method works I found there were too many exceptions(eg. I'm not really leaving a field requiring modification, I am simply moving to another application entirely). The approach I am now using is to maintain a linked list of controls requiring validation and checking this list on SetFocus. I find that doing this handles the exceptions and has the virtue of simplicity. Here is a code snippet, void DIEdit::OnSetFocus(CWnd* pOldWnd) { CMaskedEdit::OnSetFocus(pOldWnd); PDIFormView view = View(); if (view) view->ValidateDepControls(this); } BOOL DIView::ValidateDepControls (PDIEdit e) { int i = 0, n; PDIEdit c; BOOL ok = TRUE; if (Validating() || SkipValidation()) return ok; Validating(TRUE); n = DepControlCount(); while (ok && (i < n)) { c = DepControl(i++); if (c && (c != e)) ok = c->Validate(); } if (!ok) { c->SetFocus(); c->ValidationAlert(); } Validating(FALSE); return ok; } BOOL DIEdit::Validate () { return IsValid(); } void DIEdit::ValidationAlert () { if (!IsValid()) Alert("Validation failed !."); } Hope this helps, Dave
Ken Freeman -- kfreeman@viewlogic.com Tuesday, February 27, 1996 A third approach to data validation which I've used successfully is to do it during Idle processing. You won't exercise this code when moving to another app, so that's not an issue. Get a pointer to the control with focus, and save one to the control that had focus the last time your OnIdle was called. If they differ, validate the control that previously had focus. It's easy to add some logic so you don't validate when moving to the Help or Cancel buttons, for example. Idle processing is also a useful place to enable/disable controls based upon the state of other controls (this checkbox checked, a valid string in that edit box, etc.) I find this makes the logic much cleaner than handling at edit changed, combo box sel changed, etc. Mike Blaszczak wrote: > > [Mini-digest: 2 responses] > > All of the behaviour you've described is "By design". That is, it's the way > that Windows is designed to work. > > WM_KILLFOCUS is sent when a control loses focus--it's sent wether the user > tabs out of the control, the control has focus and is losing it because the > control is being destroyed, or another window (such as a message box) in the > same application has come up. > > You should maintain some state flags in your CDialog member data. In > DoDataExchange, you should check this flag and react appropriately if your > kill focus handler is being handled. If you write DoDataExchange() to not pop > up an error when you're handling WM_KILLFOCUS, you'll avoid the endless loop > you're entering. As it stands, your code is responding to WM_KILLFOCUS by > killing focus... and that just doesn't make sense. > > Forcing the focus someplace else is _NOT_ the answer because that'll just make > more kill focus messages for your control, or make other windows not work they > way they're designed to work. > > .B ekiM > TCHAR sz[] = _T("So, I come home to watch Cops, but figure skating is on > instead!"); > > -----From: daveferg@niagara.com > > This is an often repeated question. The general approach to validation > is to post a use message from OnKillFocus. This allows resolution of > the SetFocus/KillFocus before entering into another SetFocus/KillFocus. > There is an article on this subject on MSDN and I believe it is > mentioned in some MFC FAQ. > > Although the above method works I found there were too many > exceptions(eg. I'm not really leaving a field requiring modification, > I am simply moving to another application entirely). The approach I am > now using is to maintain a linked list of controls requiring validation > and checking this list on SetFocus. I find that doing this handles the > exceptions and has the virtue of simplicity. Here is a code snippet, > > void DIEdit::OnSetFocus(CWnd* pOldWnd) > { > CMaskedEdit::OnSetFocus(pOldWnd); > > PDIFormView view = View(); > > if (view) view->ValidateDepControls(this); > } > > BOOL DIView::ValidateDepControls (PDIEdit e) > { > int i = 0, n; > PDIEdit c; > BOOL ok = TRUE; > > if (Validating() || SkipValidation()) return ok; > Validating(TRUE); > n = DepControlCount(); > while (ok && (i < n)) { > c = DepControl(i++); > if (c && (c != e)) ok = c->Validate(); > } > if (!ok) { > c->SetFocus(); > c->ValidationAlert(); > } > > Validating(FALSE); > return ok; > } > > BOOL DIEdit::Validate () > { > return IsValid(); > } > > void DIEdit::ValidationAlert () > { > if (!IsValid()) Alert("Validation failed !."); > } > > Hope this helps, > Dave
| Вернуться в корень Архива |