3

在我当前的项目中,过去几天我一直在为编辑框子类化而苦苦挣扎。到目前为止,我成功地将我的编辑框子类化并验证了输入,使其只接受数字、逗号、减号和键盘命令。

但是很长一段时间以来,我一直在改进输入验证。我希望我的编辑框表现如下:

  • 仅在第一个位置接受减号
  • 只接受一个前导零
  • 只接受一个逗号
  • 前导零后强制逗号
  • 通过“返回”、“删除”、全选然后在其上粘贴某些内容来删除单个字符或文本选择时管理这些情况

我当前形式的代码如下所示,几乎没有提供我上面指定的任何高级验证要求:

inline LRESULT CALLBACK decEditBoxProc(HWND hWnd,
                                       UINT msg, 
                                       WPARAM wParam, 
                                       LPARAM lParam,
                                       UINT_PTR uIdSubclass,
                                       DWORD_PTR dwRefData)
{
    if(msg == WM_CHAR)
    {
        decEditBoxData* data = reinterpret_cast<decEditBoxData*>(ULongToPtr(dwRefData));

        bool isDigit          = (wParam >= '0' && wParam <= '9');
        bool isZero           = ((wParam == '0') && !data->blockZero);
        bool isSign           = (wParam == '-');
        bool isComma          = ((wParam == '.' || wParam == ',') && !data->blockComma);
        bool isValidCommand   = (wParam == VK_RETURN  
                                || wParam == VK_DELETE 
                                || wParam == VK_BACK);


        // Restrict comma to one.
        if(isComma && data->nCommas > 0)
            return FALSE;
        else if(isComma && data->nCommas == 0)
            data->nCommas++;

        // Restrict trailing zeroes to one.
        if(isZero && data->nTrailingZeroes > 0)
            return FALSE;
        else if(isZero && data->nTrailingZeroes == 0)
            data->nTrailingZeroes++;

        // Filter everything but digits, commas and valid commands.
        if(!isDigit && !isValidCommand && !isComma)
            return FALSE;
    }
    return DefSubclassProc(hWnd, msg, wParam, lParam);
}

非常感谢有关如何通过算法解决此问题的任何想法。

更新

感谢 David Heffernan 和 IInspectable 的建议,我能够(几乎)解决我的问题,而无需对编辑控件进行子类化。

在对话框过程中(即包含编辑控件):

switch(msg)
{
case WM_COMMAND:
   switch(LOWORD(wParam))
   {
      case IDC_IN_REAL:
         if(HIWORD(wParam)==EN_CHANGE) onEditChange(hDlg, IDC_IN_REAL);
         break;

      case IDC_IN_IMAG:
         if(HIWORD(wParam)==EN_CHANGE) onEditChange(hDlg, IDC_IN_IMAG);
         break;
    }
    break;
}

使用 onEditChange:

void onEditChange(HWND hDlg, int ctrlID)
{
    HWND hEdit    = GetDlgItem(hDlg, ctrlID);
    size_t len    = GetWindowTextLength(hEdit)+1;
    wchar_t* cstr = new wchar_t[len];
    GetWindowText(hEdit, cstr, len);

    std::wstring wstr(cstr);

    if(!(tools::isFloat(wstr)))
    {
        EDITBALLOONTIP bln;
        bln.cbStruct = sizeof(EDITBALLOONTIP);
        bln.pszTitle = L"Error";
        bln.pszText  = L"Not a valid floating point character.\nUse '.' instead of ','";
        bln.ttiIcon  = TTI_ERROR;
        Edit_ShowBalloonTip(hEdit, &bln);
    }
    delete [] cstr;
}

和 isFloat():

bool tools::isFloat(std::wstring str)
{
    std::wistringstream iss(str);
    float f;
    wchar_t wc;
    if(!(iss >> f) || iss.get(wc))
        return false;
    return true;
}

我可能会为用户添加更多视觉反馈,但这并不重要。

然而,这个问题还没有回答。我的意图是允许“,”作为可能的小数点。

4

1 回答 1

-1

你需要一个状态机。首先声明你的状态。

enum InputState
{
  NoCharacters
  MinusSign
  LeadingZero
  PreDecimalPoint
  PostDecimalPoint
}
InputState mState = NoCharacters

每当用户输入字符时,根据 mState 的值使用 switch 块调用不同的验证函数。

bool ValidCharacter(char input)
{
  switch (mState)
  {
        case NoCharacters:
          return NoCharacters(input);
        case MinusSign:
          return MinusSign(input);
        /// etc
  }
}

例如,当 mState == NoCharacters 时调用的函数将接受任何数字、小数点或减号。然后,如果字符是减号,它会将 mState 更改为 MinusSign,如果是零,它将更改为 LeadingZero,等等。

于 2014-06-20T20:35:56.897 回答