I have a small problem that I've been wracking my brains about and can't
seem to find a solution.
In a nutshell, the situation is this:
. I have multiple CEdit's in a dialog box
. Those CEdit's have ON_EN_KILLFOCUS(id,handler) set on them
so that when the user leaves the box, I can do some data
verification
. All CEdit's are in sequential TAB order.
Now, the problem arises when the user attempts to leave any of the edit
boxes. When they do, my KILLFOCUS handler checks the data, if its wrong, it
SetSel()'s the bad part and then SetFocus()'s the control. Which then (and
here is the problem) sends a EN_KILLFOCUS to the next one in the dialog box
(which received the focus after the original one lost it).
This loop then repeats until a stack overflow occurs.
So, the problem is that the focus is bouncing back between the two controls.
How can I stop this behavior? I know my explanation isn't very good, I have
a difficult time writing things like this, so if you are wanting more
detailed information, please ask, I'll be happy to do what I can.
Also, if possible, please CC: this via email to me... thanx!
Peace!
-- n i c h o l a s j l e o n
elegance through simplicity http://www.mrnick.binary9.net
good fortune through truth icq#2170994
nich...@binary9.net
First of all, it's usually a bad idea to call SetFocus from within a
OnSetFocus or OnKillFocus handler. Under some circumstances, this can leave
the focus in an indeterminate state; even if you avoid that, the slightest
logic bug in your code can wind up in an infinite loop like the one you're
seeing.
Here's a technique I've seen used to successfully avoid these sorts of
problems:
*Create a "m_bOverrideFocus" member variable for your window's class,
and initialize it to FALSE. All your OnSetFocus and OnKillFocus handlers
should check the value if this variable; if it's TRUE, they should simply
allow the focus change to proceed normally, without taking any action.
*Define a custom message, whether by registering one or just using one
in the WM_APP range. Let's say you call it CM_MYSETFOCUS. The handler
for that message should be along the lines of:
// Sets the focus to a particular window. If wParam is nonzero, sets the
// focus to the child control with that dialog item ID; otherwise, sets the
// focus to the window pointed to by lParam.
afx_msg LRESULT CMyWnd::OnMySetFocus(WPARAM wParam, LPARAM lParam)
{
ASSERT(!m_bOverrideFocus);
m_bOverrideFocus = TRUE;
CWnd * pWnd = NULL;
if (wParam) {
pWnd = GetDlgItem(wParam);
} else {
pWnd = (CWnd *)lParam;
}
if (pWnd && pWnd->IsWindow()) {
pWnd->SetFocus();
} else {
ASSERT(FALSE);
}
m_bOverrideFocus = FALSE;
return 1;
}
So now, whenever one of your OnSetFocus or OnKillFocus handlers is
currently calling SetFocus, it should instead be PostMessage-ing a
CM_MYSETFOCUS message.
--
\o\ If you're interested in books and stories with transformation themes, \o\
/o/ please have a look at <URL:http://www.halcyon.com/phaedrus>. Thanks! /o/
\o\ FC1.21:FC(W/C)p6arw A- C->++ D>++ H+ M>+ P R T++++ W** Z+ Sm RLCT \o\
/o/ a cmn++++$ d e++ f+++ h- i++wf p-- sm# /o/
| First of all, it's usually a bad idea to call SetFocus from within a
| OnSetFocus or OnKillFocus handler. Under some circumstances, this can
leave
| the focus in an indeterminate state; even if you avoid that, the slightest
| logic bug in your code can wind up in an infinite loop like the one you're
| seeing.
Ok, I can see that. Its similiar to creating recursive routines that depend
on a state of a variable that may be in flux when the routine executes or
something that may be potentionally interrupted while executing; ala
interrupt handlers.
| Here's a technique I've seen used to successfully avoid these sorts
of
| problems:
Hehe... ok, you basically just wrapped the whole thing up into a mutex-style
lock :) I'm not a 100% on the (low-level looking) Windows calls you use, but
I think I can muddle myself through (in case you care, I'm a Unix programmer
who got assigned this lovely task because I was the 'best suited' :)
Thank you again .... !
> In a nutshell, the situation is this:
>
> . I have multiple CEdit's in a dialog box
> . Those CEdit's have ON_EN_KILLFOCUS(id,handler) set on them
> so that when the user leaves the box, I can do some data
> verification
> . All CEdit's are in sequential TAB order.
>
> Now, the problem arises when the user attempts to leave any of the edit
> boxes. When they do, my KILLFOCUS handler checks the data, if its wrong, it
> SetSel()'s the bad part and then SetFocus()'s the control. Which then (and
> here is the problem) sends a EN_KILLFOCUS to the next one in the dialog box
> (which received the focus after the original one lost it).
>
> This loop then repeats until a stack overflow occurs.
There is a knowledgebase article and sample app that shows how to overcome
this problem. As you have found, you can't do a SetFocus during killfocus
processing. Check out:
Title: SAMPLE: Control-by-Control Validation in MFC
Document Number: Q114962
Jim [VC/MFC MVP]
To send mail, change spam-me-not to msn