Question

INTRODUCTION AND RELEVANT INFORMATION:

I have an edit control that needs to accept only signed decimal numbers ( something like -12.35 ).

I have decided to implement this via subclassing.

The WM_CHAR handler seems to works well, and I need to handle several other messages to completely protect user from entering invalid text. One such message is WM_PASTE.

So far I was able to properly get the text from the clipboard and to discard or pass the message depending if the copied string is indeed decimal number.

Edit control has limited input to 12 characters. This is done via EM_SETLIMITTEXT message.

I use pure Winapi and C++. No libraries like boost etc are allowed.

PROBLEM:

So far I test the case where edit control is empty and I discard pasting if the content is invalid. However, user can select a portion of the text in the edit control and then perform pasting. Something like this ( grey characters represent selection ):

Text in edit control: 12345678.9

Clipboard text : -1A

The resulting string, if I would allow pasting, would be 123-1A78.9 which is invalid format.

This is the part I need help with:

My parsing properly recognizes valid format but I do not know how to properly merge two strings into one so I could test it.

QUESTIONS:

  1. How can I properly form the resulting string from pasting so I can test its validity ?

  2. Is there a function that can do the validity test for me ( it should be locale aware! ) ?

Note: I do not mind parsing the text myself but why "reinventing the wheel" if there is no need for it?

MY EFFORTS TO SOLVE THIS:

  1. Browsing through Internet I found many std:: functions that concatenate/cut off/ etc string but none of them seem to satisfy my needs for forming the resulting string. The closest thing I found was string:: insert(...) but I do not know how to use it.

  2. As for the second question, I found std:: strtod by browsing through StackOverflow questions and it seems that it can be used to check the validity of the string. And it seems that it is locale aware as well, but I am not sure if it is what I seek.

To keep this post as brief as possible I provide the link to this question of mine that has relevant code snippets.

Thank you for your time and help.

If further info is required I will update the post.

Best regards.

Was it helpful?

Solution

Try something like this:

case WM_PASTE:
{
    std::wstring cbtext;

    if( !OpenClipboard(hwnd) ) // open clipboard
        return 0;

    // get clipboard data
    HANDLE hClipboardData = GetClipboardData(CF_UNICODETEXT);
    if( hClipboardData )
    {
        // Call GlobalLock so that to retrieve a pointer
        // to the data associated with the handle returned
        // from GetClipboardData.

        cbtext = (LPWSTR) GlobalLock(hClipboardData);

        // Unlock the global memory.
        GlobalUnlock(hClipboardData);
    }

    // Finally, when finished I simply close the Clipboard
    // which has the effect of unlocking it so that other
    // applications can examine or modify its contents.

    CloseClipboard();

    if (cbtext.empty())
        return 0;

    // format the new text with the clipboard data inserted as needed

    int len = GetWindowTextLengthW(hwnd);
    std::wstring newtext(len, 0);
    if (len > 0)
        GetWindowTextW(hWnd, &newtext[0], len);

    DWORD start, end;
    SendMessageW(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);

    if (end > start)
        newtext.replace(start, end-start, cbtext);
    else
        newtext.insert(start, cbtext);

    // parse the new text for validity

    // code for parsing text 
    if( IsTextValid )
        SetWindowTextW( hwnd, newtext.c_str() );

    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top