?
Solved

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

Posted on 2006-04-19
11
Medium Priority
?
373 Views
Last Modified: 2013-11-20
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
0
Comment
Question by:rickatseasoft
  • 6
  • 3
  • 2
11 Comments
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16486439
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
 

Author Comment

by:rickatseasoft
ID: 16492963
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
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16495397
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Author Comment

by:rickatseasoft
ID: 16496561
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
 
LVL 45

Assisted Solution

by:AndyAinscow
AndyAinscow earned 1200 total points
ID: 16497314
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
 
LVL 49

Accepted Solution

by:
DanRollins earned 800 total points
ID: 16501801
>> ..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
 

Author Comment

by:rickatseasoft
ID: 16502902
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
 

Author Comment

by:rickatseasoft
ID: 16502961
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 16503589
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
 

Author Comment

by:rickatseasoft
ID: 16503769
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
 

Author Comment

by:rickatseasoft
ID: 16503782
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

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
If you use Adobe Reader X it is possible you can't open OLE PDF documents in the standard. The reason is the 'save box mode' in adobe reader X. Many people think the protected Mode of adobe reader x is only to stop the write access. But this fe…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Suggested Courses

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question