在响应EN_UPDATE消息时避免递归

Avoiding recursion when responding to EN_UPDATE message

本文关键字:递归 消息 UPDATE 响应 EN      更新时间:2023-10-16

我正在尝试创建一个edit control,它将接受符号号分隔符号格式的带符号十进制数(例如-1.5)。

经过对互联网的广泛研究,我发现很少有令人满意的屏蔽编辑控件的例子,,但它们是在MFC中完成的。

由于我不知道MFC,我很难将该代码翻译成纯Win32 API,所以我决定尝试用自己的方式从头开始。

在仔细研究了MFC示例后,我得出结论,它们在响应EN_UPDATE消息时执行文本验证。

当我尝试执行同样的操作时,我的程序立即退出,没有任何警告或错误消息。我已经得出结论,我的问题一定是递归。

为了证实这一点,我在主窗口的程序中编写了一个小的处理程序来测试:

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...

这就是当我在Debug模式下启动程序时发生的情况:

在我键入字母a之后,编辑控件的文本将变为e

这证实了我关于递归的结论:在我按下a后,它被转换为b,然后另一个EN_UPDATE发射,它重复这个过程,所以b变成c,以此类推,直到static变量到达4,所以结果是e

我的问题很简单:

为了避免这种类型的递归,我应该如何处理EN_UPDATE或修改我的程序?

编辑(2014年2月18日):

我已经根据成员Jonathan Potter的说明修改了上述EN_UPDATE处理程序。

尽管递归问题消失了,但输出并不是我想要的。

我已经验证了我的代码的正确性,在一个简单的控制台应用程序中用他的继任者替换了一个字符,并在点击按钮时进行了同样的操作(我很难快速添加一个按钮和一个用于点击它的处理程序)。

因此,问题一定是给定指令的执行,因此我提交了更正后的代码,希望有人能指出我做错了什么:

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;

现在,在按下a之后,它正确地变成了b,但在我按下b之后,我没有得到预期的结果bc,而是cc

这是意料之中的,因为在用户按下按键之后生成EN_UPDATE以显示文本。

因此,当按下a时,它将转换为b。当我随后按下b时,会生成一条新的EN_UPDATE消息,因此我的处理程序会重新启动,这意味着它会获取新的字符串bb并将其正确转换为cc

有没有一种方法可以在使用当前文本进行操作时暂时禁止创建新的EN_UPDATE消息,以便在上面的示例中,当我按下a然后按下b时,我得到的结果是bc而不是cc

编辑结束

感谢您的时间和帮助。

致以最良好的问候。

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 )

也许我误解了这种情况,为什么不使用EN_CHANGE并向用户指示该值不正确,如下所示?

[以下代码适用于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;
}

尝试为编辑控件设置ES_MULTILINE。
或者
您可以在处理编辑控件通知之前检查标志。

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..

在WM_CREATE中设置m_bSentFromSWT=FALSE。

我确信这些年后,OP不可能使用MFC。

然而,对于任何遇到这个问题的人来说,最简单的解决方案是在消息处理程序的顶部有一个这样的块:

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

就在您在处理程序中调用SetWindowText之前,请设置updateing=true。它可能感觉有点难看,但它MFC。