NextDlgCtrl() goes to wrong control----Why

I have a class derived from a class that is, itself, derived from CEdit.  This class is supposed to allow exactly one character to be entered, one of "YyNn", and then move on to the next control.  I am using OnChange to accomplish this

void CYesNoEdit::OnChange()
{
      // TODO: If this is a RICHEDIT control, the control will not
      // send this notification unless you override the CEdit::OnInitDialog()
      // function and call CRichEditCtrl().SetEventMask()
      // with the ENM_CHANGE flag ORed into the mask.
      
      // TODO: Add your control notification handler code here
      char cc[2];
      GetWindowText(cc,2);
      if(!instr("yYnN",cc[0])){
            cc[0]=0;
            SetWindowText(cc);
      }else{
            cc[0]=toupper(cc[0]);
            SetWindowText(cc);
            CWnd *pParent;
            pParent=GetOwner();
            ((CDialog *)pParent)->NextDlgCtrl();      
      }
}

It works perfectly except for the fact that it actually sets focus to the previous control rather than the next control.  If I comment out the NextDlgCtrl() line, the focus stays on this control, and if I press the TAB key, it goes properly to the next control.  I've confirmed that pParent is, in fact, the parent CDialog.  BTW, this control is the very last control of the CDialog parent, although the MFC doc says that it will go to the first if on the last.

Any ideas will be greatly appreciated.

Rick
rickatseasoftAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AndyAinscowFreelance programmer / ConsultantCommented:
I don't see why it should not work.

Do you still get this behaviour if the edit is NOT the last control in the tab order?
0
rickatseasoftAuthor Commented:
Andy:

I've tried several different tab orders, and in all cases, entering any one of "YyNn" in this particular control goes to the previous control in the TAB order.

Thanks, Rick
0
AndyAinscowFreelance programmer / ConsultantCommented:
I don't understand why you get this behaviour.  (Could you add a couple of extra controls just to see if it ends up two or three controls away - is it sending more than one NextDlgCtrl to the parent, by chance it sends enough to cycle until the previous control is reached.)

Ways around it.
1) Send a custom message (eg. WM_APP+10) to the parent window.  In the parent window the message handler calls NextDlgCtrl().

2) Use SendInput to fake a keypress of the TAB key which is passed to the parent window
0
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

rickatseasoftAuthor Commented:
Andy:

It turns out that this function was causing itself to be called because it was updating the window with new text (In the debugger, I found approx 14 calls to this function).  Adding m_bLocalUpdate is how I have fixed it.

void CYesNoEdit::OnChange()
{
      // TODO: If this is a RICHEDIT control, the control will not
      // send this notification unless you override the CEdit::OnInitDialog()
      // function and call CRichEditCtrl().SetEventMask()
      // with the ENM_CHANGE flag ORed into the mask.
      
      // TODO: Add your control notification handler code here
      if(m_bLocalUpdate)return;
      m_bLocalUpdate=TRUE;
      char cc[2];
      GetWindowText(cc,2);
      if(!instr("yYnN",cc[0])){
            cc[0]=0;
            SetWindowText(cc);
      }else{
            cc[0]=toupper(cc[0]);
            SetWindowText(cc);
            CWnd *pParent;
            pParent=GetOwner();
            ((CDialog *)pParent)->NextDlgCtrl();      
      }
      m_bLocalUpdate=FALSE;
}

I wonder if this is a rational and reasonable approach, or is there a better way.  In retrospect, it is clear that this function updates the window, and I want to use it because it will keep invalid data from being pasted, so this seems like a reasonable way to proceed.

Any opinions, Rick
0
AndyAinscowFreelance programmer / ConsultantCommented:
I am a bit worried with you using the OnChange to modify the window contents - using the bool flag to prevent re-entry ought to work.  
I think I would use the OnChar function (or OnKeyDown) to check the character being typed and throw it away if not suitable.  Then just use the OnChange to determine if one should move to the next control.


I seem to recall you use the DUNDAS classes - check the COXMaskedEdit there.  I think you should be able to use that as a basis for what you want.
0
DanRollinsCommented:
>> ..is it sending more than one NextDlgCtrl to the parent,...

>>...In the debugger, I found approx 14 calls to this function

It looks like AndyAinscow identified the problem.... nice work Andy.

I also agree that the best way to handle this is in the OnChar() handler.  The boolean flag to prevent recursion is, well, ugly :-)

One generic way around recursion like this is to have the control POST a message to itself (usually a custom message) -- that way it will be handled AFTER all of the flurry of activity associated with the event (as opposed to *during* the event itself).  That doesn't really apply in this situation, but it's often a useful technique.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
rickatseasoftAuthor Commented:
Dan:

I sort of agree that the boolean in ugly, but I am concerned that if I use OnChar(), then I will only be trapping keystrokes.  I have a strong need to verify the validity of the data, and I am concerned that a person will cut and paste something inappropriate here.  

Of course, I can check it with OnKillFocus(), but that has some limitations also.  I can also check it in the calling code, but that makes this class somewhat worthless.

Thanks, Rick
0
rickatseasoftAuthor Commented:
Andy:

What a memory you have!  I originally looked at OXMaskedEdit and considered adding some sort of character to the mask like "L"ogical, "Y"es/No, or something like that.

There were three things that drove the decision to create a new sub-class:  I didn't want to take the time to understand all of the things that MaskedEdit was doing, and doing well I might add; I didn't want to deal with likelihood that future problems in the vicinity of MaskedEdit would be complicated by us wondering whether the problem was induced by our change, or was the problem somewhere else; and finally, we will use this a lot, and using MaskedEdit would double the workload in the sense of having to not only declare a Control Variable of the COXMaskedEdit Class, but also call SetMask().

Thanks again for your help, Rick
0
DanRollinsCommented:
It might be possible to look at calling GetUpdate() (EM_GETUPDATE) ... I don't have time to check it out, but there is a chance that the internal "updated" flag does not get set unless the the data actually changes (eg, changing from "N" to "N" might not be considered a change, so recursion would be avoided).

BTW:
The standard way to obtain a boolean (Y/N) from a user in a Windows dialogbox is to provide a checkbox control :-)
0
rickatseasoftAuthor Commented:
Dan:

Of course you are right.  The problem is that there are around 40 of these in a single dialog, some require more than a yes/no, and more importantly---because of our desire to be backwardly compatable with Unix, we want the user to be able to <RETURN> through the fields, answering only those that need an answer.  That is, some will be <Y> some will be <N>, and some will be <BLANK>.  I know that Radios, etc. will do this, but, in this case, we want to go with a single character dialog.

To both Dan and Andy, thanks for all the input.

Rick
0
rickatseasoftAuthor Commented:
One last point:

At some point, we will modify this control to accept multiple answers that will each be a single character.

Anyway, thanks again.

Rick
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.