2

I'm trying to block certain types of characters from being inserted into my Edit Control by overwriting OnChar and OnKeydown. I'm trying to block more than one point '.' and anything that is not a number.

First I check if there is already a '.' in the Edit Control that has the focus by setting a variable defined in the dialog class to false:

void MyMainDialog::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
  CWnd * eb1 = GetDlgItem(IDC_EDIT1); //Reference dimension 1 box;
  CWnd * eb2 = GetDlgItem(IDC_EDIT2); //Reference dimension 2 box
  CWnd * eb3 = GetDlgItem(IDC_EDIT3); //Reference dimension 3 box
  CString temp;

  CWnd * focusedHand = MyMainDialog::GetFocus(); //Reference edit box being focused

  if(focusedHand == eb1)
  {
    eb1->GetWindowTextA(temp);
    if(temp.Find('.') != -1)
      checkPoint = true;
    else
      checkPoint = false;
  }
  else if(focusedHand == eb2)
  {
    eb2->GetWindowTextA(temp);
    if(temp.Find('.') != -1)
      checkPoint = true;
    else
      checkPoint = false;
  }
  else if(focusedHand == eb3)
  {
    eb3->GetWindowTextA(temp);
    if(temp.Find('.') != -1)
      checkPoint = true;
    else
      checkPoint = false;
  }

  CDialogEx::OnKeyDown(nChar, nRepCnt, nFlags);
}

At OnChar I'm checking the character being typed. If it is not a number of if it's a point but there was already a point, then I don't call the OnChar from CDialog:

void MyMainDialog::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
   if(nChar == '.' && checkPoint == false) //Is a point and there is no other point
  {
     CDialogEx::OnChar(nChar, nRepCnt, nFlags);   
  }

  if((nChar < '0' || nChar > '9')) //Is not a number
  {
     //Show message to user
  }
  else //Is a number
  {
    CDialogEx::OnChar(nChar, nRepCnt, nFlags);
  }
}

Well, my code is not working. It compiles and it doesn't crash when typing in the edit control, but it simply doesn't do anything. I'm wondering if the right way to overwrite it would be to prevent the call of CDialogEx::OnChar() or if I should make nChar = 0 so that the character displayed will be null. But on top of that the message that I'm trying to display at OnChar is also not displaying, meaning that MyMainDialog::OnChar() is not even being called. Should I overwrite CDialogEx::OnChar() instead?

Thanks for your attention

mskfisher
  • 3,291
  • 4
  • 35
  • 48
Artie
  • 493
  • 1
  • 7
  • 18
  • Have a look at the [filter edit control](http://www.codeproject.com/KB/edit/FilterEdit.aspx) on codeproject. – Andre Dec 08 '11 at 07:27

3 Answers3

2

I found the solution. The reason why the code doesn't seem to be making any effect in my application is because it is making effect only to MyMainDialog. When typing in the Edit Control, the OnChar() being called if from CEdit, so that is the one I have to intercept. You are not allowed to overwrite CEdit::OnChar(). The solution is to create a class that derives from CEdit and then intercept the OnChar() from that class. You you also have to use your class instead of CEdit for manipulating your Edit Control.

My code was then reformulated to this:

OnChar():

void CustomEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
  if(nChar == '.' && checkPoint == true) //Is a point and there is already a point
  {
     //Show message  
  }
  else if(nChar == '.' && checkPoint == false) //Is a point but there is no point
  {
    CEdit::OnChar(nChar, nRepCnt, nFlags);
  }

  if((nChar < '0' || nChar > '9') && nChar != 8) //Is not a number or backspace
  {
     //Show message
  }
  else //Valid
  {
     CEdit::OnChar(nChar, nRepCnt, nFlags);
  }
}

OnKeyDown():

void CustomEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
  CString temp;

  this->GetWindowTextA(temp);
  if(temp.Find('.') == -1)
    checkPoint = false; //There is no point
  else
    checkPoint = true; //There is a point

  CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}

Hope this helps anyone with a similar question. By the way, there are many classes and automated solutions in the internet, I did this manually for learning purposes.

Artie
  • 493
  • 1
  • 7
  • 18
2

A much easier way is to handle your input with an OnChange event:

// do not add numbers; ascci numbers is 48 - 57
if ((m_strYOURCONTROL[m_strYOURCONTROL.GetLength() - 1]) > 47 && 
         m_strYOURCONTROL[m_strYOURCONTROL.GetLength() - 1]) < 58)
{
    m_strYOURCONTROL = m_strYOURCONTROL.Mid(0, m_strYOURCONTROL.GetLength() - 1);
}

This will not allow numbers. With this implementation you can handle easier the input to the editbox

Sunscreen
  • 3,452
  • 8
  • 34
  • 40
  • Well. That was my initial approach, but the code ended up very big and ugly. Not only I have more than one edit control, but how you would then handle for checking the extra decimal point? Then I kept adding boolean variables, checks and so on. Very hard to maintain as well. A viable choice nonetheless. – Artie Dec 12 '11 at 03:36
  • I can add bad characters in the middle of the digits with your solution, right? – mBardos Jan 30 '20 at 08:32
1

Another solution is to handle WM_CHAR earlier, in PreTranslateMessage.

l33t
  • 18,692
  • 16
  • 103
  • 180
  • As I kept researching ways to do that without having to create a derived class, overwriting PreTranslateMessage() always came up as a very non-elegant and dangerous solution that should be avoided at all costs. I'm not completely sure why that is, probably hard to maintain. – Artie Dec 12 '11 at 03:31
  • 1
    There are no elegant solutions in MFC :P – l33t Nov 05 '12 at 13:15