0

I have an EditBox in a MFC-dialog. The user is supposed to enter a number. I'm trying to automatically add separators to the number while the user is inputting it:

When the number is more than 3 digits long, a separator is added between the hundreds and the thousands digit; a second one between the hundredthousands and the millions when it gets longer than 6 digits and so forth (so that 1234567 becomes 1,234,567 for example).

This is done in a function executed by ON_EN_CHANGE and basically works fine already. But the problem is that the caret position is set to the beginning of the EditBox once my function changes the length of the string in it, preventing continous typing.

I tried simulating the press of the end-key to send the caret to the end of the EditBox, which works as long as the user only enters a number from left to right. But it won't work when the user is trying to add, remove or edit digits in the middle of the number. I need the caret position at the exact spot of the number where it was before the user pressed a key.

I tried calculating the new caret position from the previous one (gotten with CEdit::GetSel()) and the previous length of the number:

OnEnChange()
{
    int prevCursPos {HIWORD(m_editCtrl.GetSel())};
    int prevStrLen {m_editCtrl.GetWindowTextLengthW()};
    UpdateData(TRUE);
    // Adding/Removing of separators as needed
    UpdateData(FALSE);
    int difference {m_editCtrl.GetWindowTextLengthW() - prevStrLen))};
    if(difference > 0) // a separator has been added to the string
        m_editCtrl.SetSel(-1, prevCursPos + 1);
}

However, the SetSel() function doesn't seem to have any effect. I also tried to send an EM_SETSEL message instead, but I couldn't figure out how to make that work either, the caret always resets itself to the beginning of the EditBox.

Does anyone have another idea on how to accomplish what I'm trying to do?

Estelyen
  • 55
  • 1
  • 7
  • 1
    If you need to move the caret to a specific location use the same value for `nStartChar` and `nEndChar`. That fixes the immediate issue, although the code logic is still wrong: It doesn't take into account, whether the separator was inserted to the left or right of the current caret position, and it doesn't account for paste operations that insert more than one character at a time. – IInspectable Jan 11 '22 at 10:41
  • Are you handling the `Backspace` or `Del` key? Your separator may be removed... – Vlad Feinstein Jan 11 '22 at 19:14
  • @IInspectable: Thanks, that did it. The code logic is indeed wrong, I was first trying to see if this issue could be solved at all or if I needed to do a totally different approach before I dig deeper into that. – Estelyen Jan 12 '22 at 08:31

1 Answers1

0
  1. It is unclear how you are handling "/ Adding/Removing of separators as needed".
  2. SetSel with the first parameter set to -1 will position the caret at the beginning of the string if the string changes after calling UpdateData(false)

Create CString type of the variable (m_csEdit for example) for this edit control and

    int iLen = m_csDDx.GetLength();
    m_editCtrl.SetSel(iLen, -1);

or

    m_editCtrl.SetSel(iLen, iLen);

You can calculate the length differently from what I suggested. Consider using masked edit control (maybe).

Forgot to mention. Use GetNumberFormatEx to format number with thousand delimiter.

JohnCz
  • 1,613
  • 1
  • 9
  • 9
  • Using the same value for both parameters instead of -1 did the trick, thanks. My mistake for not figuring that out I guess :P. Also thank you for suggesting GetNumberFormatEx, I will definitely give that a look. – Estelyen Jan 12 '22 at 08:29