【问题标题】:Subclassed edit control accepts dot eventhough it shouldn't子类编辑控件接受点,即使它不应该
【发布时间】:2013-09-05 09:06:19
【问题描述】:

我将编辑控件子类化为只接受数字。

另外,在子类化过程中,我解析剪贴板数据以删除禁用字符。

我已经实现了预期的行为,或者至少我认为是这样,但唯一的问题是我也可以在编辑控件中键入 dot。

我不知道我的代码有什么问题,所以我在这里发布它希望其他人可以帮助我。

剪贴板解析返回正确的数据,但给我带来麻烦的是 WM_CHAR。

请帮忙,我就是不知道我的代码有什么问题。

谢谢。

这是子类化过程的代码:

    LRESULT CALLBACK MyEditProc ( HWND hwnd, 
                                  UINT message, 
                                  WPARAM wParam, 
                                  LPARAM lParam, 
                                  UINT_PTR uIdSubclass, 
                                  DWORD_PTR  dwRefData )
    {
        switch (message)
        {
        case WM_PASTE:
              {
                 if ( OpenClipboard( NULL ) ) 
                 {

                     HANDLE hClipboardData = GetClipboardData(CF_UNICODETEXT);

                     wchar_t *pchData =
                                        (wchar_t*)GlobalLock(hClipboardData);

                     GlobalUnlock(hClipboardData);

                     CloseClipboard();

                     int i = 0, j = 0;

                     wchar_t *temp = new wchar_t[51]; // parsed string

                     memset( temp, '\0', sizeof(temp) );

                     // integer numbers are parsed here

                     while( ( i < (int)wcslen(pchData) )
                          && ( j < 10 ) ) // I just need first 10
                     {
                         if( isdigit( pchData[i] ) )
                            temp[j++] = pchData[i];
                         i++;
                     }

                     temp[j] = '\0';

                     // replace selection with parsed text

                     SendMessage( hwnd, EM_REPLACESEL, 
                                  (WPARAM)TRUE, (LPARAM)temp );

                     // set caret at the end of the text

                     SendMessage( hwnd, EM_SETSEL, j, j );

                     delete[] temp;
                  }
               }
               return TRUE;
               break;

        case WM_CHAR:
               {

                   if( ! ( isdigit(wParam)
                         || wParam == VK_RETURN
                         || wParam == VK_DELETE
                         || wParam == VK_BACK ) 
                         // this check bellow is needed 
                         // so I can catch WM_PASTE !
                         && ( ! ( GetKeyState( VK_CONTROL ) & 0x8000 ) ) ) 
                   {
                         return 0;
                   }
                }
                break;
        }
        return DefSubclassProc( hwnd, message, wParam, lParam);
    }

我已经像这样子类化了 WM_CREATE 上的控件:

SetWindowSubclass( hEdit, MyEditProc, 0, 0);

由于我没有将任何东西作为第 4 个参数传递给上述过程,我觉得没有必要调用 RemoveWindowSubclass

编辑:

由于 Passant 先生指出了我的解决方案中的错误,我已将其删除,以免混淆阅读这篇文章以寻找类似问题的解决方案的人。

【问题讨论】:

    标签: c++ winapi


    【解决方案1】:

    核心错误是您在 WM_CHAR 消息处理程序中测试虚拟键代码。这是不正确的,虚拟键码仅用于 WM_KEYDOWN/UP 消息中。 WM_CHAR 获取翻译后的击键,一个由活动键盘布局和键盘状态选择的字符。消息循环中的 TranslateMessage() 调用完成了这项工作。使用 GetKeyState() 同样是错误的,TranslateMessage() 已经这样做了。

    你幸运地使用了 VK_RETURN 和 VK_BACK,这些虚拟键代码与翻译后的控制代码具有相同的代码(0x0d 和 0x08)。 VK_DELETE 的运气用完了,它的代码 0x2e 与 '.' 字符相同。

    正确的代码应该类似于:

       case WM_CHAR:
       {
           if (wParam >= ' ' && !isdigit(wParam) {
               return 0;
           }
       }
       break;
    

    【讨论】:

    • 一个小问题:为什么要测试 wParam 是否大于空间?我不明白那部分,你能简要解释一下吗?谢谢你。问候。附言我的意思是这行代码: if( wParam >= ' '
    • 你不想弄乱控制代码。像 Crl+X、Ctrl+V、Ctrl+C、退格键。用于编辑和操作剪贴板。您只关心抑制真实字符,任何> = 0x20。空格字符。
    猜你喜欢
    • 2014-08-11
    • 2019-12-24
    • 1970-01-01
    • 2013-07-29
    • 2012-05-13
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 2019-06-26
    相关资源
    最近更新 更多