Link to home
Start Free TrialLog in
Avatar of rickatseasoft
rickatseasoft

asked on

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
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

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?
Avatar of rickatseasoft
rickatseasoft

ASKER

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
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
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
SOLUTION
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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
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 :-)
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
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