Pergunta

I am trying to create an edit control that will accept signed decimal numbers in the format of sign number separator number ( e.g. -1.5 ).

After extensive research on the Internet I have found few satisfying examples of masked edit controls, but they are done in MFC.

Since I do not know MFC, I have trouble translating that code into pure Win32 API, so I have decided to try doing it my own way, starting from scratch.

After carefully studying the MFC examples I have concluded that they perform text validation when responding to EN_UPDATE message.

When I try to do the same my program exits immediately, without any warning or error message. I have concluded that my problem must be recursion.

To confirm this I have wrote a small handler in my main window's procedure to test this:

case WM_COMMAND:
    switch( HIWORD( wParam ) )
    {
    case EN_UPDATE:
        if( LOWORD(wParam) == IDC_OF_MY_EDIT_CONTROL)
        {


            static int counter = 0;   // increment it each time we get EN_UPDATE

            // after we receive EN_UPDATE 4 times stop testing

            if( ( counter++) < 4 )   
            {
                wchar_t text[10];  // get sample text

                GetWindowText( (HWND)lParam, text, 10 );

                // change current char to char + 1
                // which means A will be B, B will be C and so on...

                for( int i = 0; i < wcslen(text); i++ )
                    text[i] = (wchar_t)( 1 + text[i] );   

                SetWindowText( (HWND)lParam, text );   // show changed text
            }
        }
        break;
    }
    break;

case WM_CLOSE: // WM_CLOSE and other handlers...

This is what happens when I start my program in Debug mode:

After I type letter a the text of the edit control turns into e.

This confirms my conclusion about recursion: After I have pressed a it was converted to b, then another EN_UPDATE fired off, which repeated the process so b turned into c and so on until static variable reached 4 so the result was e.

My question is simple:

How should I handle EN_UPDATE, or modify my program, in order to avoid this type of recursion ?

EDIT ( February 18th, 2014 ):

I have modified the above EN_UPDATE handler per member Jonathan Potter's instructions.

Although recursion problem disappeared, the output is not what I have desired.

I have verified the correctness of my code for substituting a character with his successor in a simple console application and by doing the same when clicking on a button ( it wasn't hard for me to quickly add a button and a handler for clicking on it ).

So the problem must be the implementation of the given instructions, therefore I submit the corrected code in hope that someone will point out what did I do wrong:

case EN_UPDATE:
    if( LOWORD(wParam) == IDC_OF_MY_EDIT_CONTROL)
    {
        static bool OK_to_process_text = true;

        if( OK_to_process_text )
        {
            OK_to_process_text = false;

            wchar_t text[10];
            memset( text, L'0', sizeof(text) );

            GetWindowText( (HWND)lParam, text, 10 );

            for( size_t i = 0; i < wcslen(text); i++ )
                text[i] = (wchar_t)( 1 + text[i] );

            SetWindowText( (HWND)lParam, text ); 

            OK_to_process_text = true;
        }
    }
    break;
}
break;

Now, after pressing a it properly turns into b, but after I press b I do not get the expected result bc but cc.

This is expected, since after user presses a key EN_UPDATE is generated to display text.

Therefore when pressing a it will convert to b. When I press b afterwards, a new EN_UPDATE message is generated, so my handler starts over, which means that it takes new string bb and properly converts it to cc.

Is there a way to suppress temporarily creation of a new EN_UPDATE message while manipulating with current text so in the example above I get the result bc instead of cc when I press a and then b?

END OF EDIT

Thank you for your time and help.

Best regards.

Foi útil?

Solução

I am trying to create an edit control that will accept signed decimal numbers in the format of sign number separator number ( e.g. -1.5 )

Maybe I am misunderstanding the situation, why not use EN_CHANGE and give the user a indication that the value is not correct, with something like the following?

[code below is for MS Visual Studio]

case EN_CHANGE:
    if( LOWORD(wParam) == IDC_OF_MY_EDIT_CONTROL)
    {   TCHAR szValue[32];
        double dd;
        GetWindowText((HWND)lParam, szValue, _countof(szValue));
        if (_stscanf(szvalue, _T("%lf"), %dd) == 1)
        {   // optionally reset an error indicator on the screen
        }
        else
        {   MessageBeep(MB_ICONEXCLAMATION);
            // optionally set an error indicator on the screen
        }
        break;
    }

Outras dicas

Try setting ES_MULTILINE for your edit control.
Or
you can check a flag before processing edit control notifications.

case WM_COMMAND:
    switch( HIWORD( wParam ) )
    {
    case EN_UPDATE:
        if( LOWORD(wParam) == IDC_OF_MY_EDIT_CONTROL)
        {

if (m_bSentFromSWT)
{
//No need to process this notification
m_bSentFromSWT = FALSE;
break;
}
            static int counter = 0;   // increment it each time we get EN_UPDATE

            // after we receive EN_UPDATE 4 times stop testing

            if( ( counter++) < 4 )   
            {
                wchar_t text[10];  // get sample text

                GetWindowText( (HWND)lParam, text, 10 );

                // change current char to char + 1
                // which means A will be B, B will be C and so on...

                for( int i = 0; i < wcslen(text); i++ )
                    text[i] = (wchar_t)( 1 + text[i] );   

                SetWindowText( (HWND)lParam, text );   // show changed text
m_bSentFromSWT  = TRUE;
            }
        }
        break;
    }
    break;

case WM_CLOSE: // WM_CLOSE and other handlers..

Set m_bSentFromSWT = FALSE in your WM_CREATE.

I'm sure all these years later, there's no possible way that the OP is using MFC.

However, for anyone who happens on this problem, the simplest solution is to have a block like this at the top of your message handler:

// Avoid Recursion
static bool updating = false;
if (updating)
{
    updating = false;
    return;
}

Just before you call SetWindowText in your handler, set updating = true. It may feel a little ugly, but it is MFC.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top