【发布时间】:2014-02-18 10:21:02
【问题描述】:
我正在尝试创建一个edit control,它将接受格式为 sign number separator number 的带符号十进制数字(例如 -1.5 )。
在 Internet 上进行广泛研究后,我发现很少有令人满意的蒙版编辑控件示例,但它们是在 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 然后按下 @987654360 时,我得到的结果是 bc 而不是 cc @?
编辑结束
感谢您的时间和帮助。
最好的问候。
【问题讨论】:
-
使用一个标志,如果你只有一个控件实例,则全局存储,否则为每个控件。检查标志是否在您的 EN_UDPATE 处理程序中设置。如果是这样,什么也不做。如果没有,设置标志,处理 EN_UPDATE,然后再次清除标志。
-
@JonathanPotter:对不起,但我有一个后续问题:我应该在哪里设置标志以响应
WM_CHAR或其他消息?至于处理EN_UPDATE,你的意思是这样的:case EN_UPDATE: if( FALSE == flag ) { flag = TRUE; /* do my stuff */ flag = FALSE; }?再次,我很抱歉打扰,但我没有完全理解你的评论。最好的问候。 -
您最终会陷入无限循环,因为您在处理 EN_UPDATE 时更改了编辑字段的内容。更改字段的内容会生成另一个 EN_UPDATE,它会再次更改字段的内容,依此类推。使用标志会阻止您重新输入 EN_UPDATE 代码。
-
类似问题的Compromise Answer
标签: c++ winapi recursion editcontrol