【发布时间】:2014-08-11 02:03:52
【问题描述】:
在我当前的项目中,过去几天我一直在为编辑框子类化而苦苦挣扎。到目前为止,我成功地对我的编辑框进行了子类化并验证了输入,使其仅接受数字、逗号、减号和键盘命令。
但是很长一段时间以来,我一直在改进输入验证。我希望我的编辑框表现如下:
- 仅在第一个位置接受减号
- 只接受一个前导零
- 只接受一个逗号
- 前导零后强制逗号
- 在删除单个字符或通过“返回”、“删除”、全选然后在其上粘贴内容时管理这些情况
我的当前形式的代码如下所示,几乎没有提供我上面指定的任何高级验证要求:
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;
}
我可能会为用户添加更多视觉反馈,但这并不重要。
然而,这个问题还没有回答。我的意图是允许“,”作为可能的小数点。
【问题讨论】:
-
这是一个非常糟糕的主意。不要阻止输入。用户输入数据的方式有很多种,你很难全部屏蔽掉。您目前还远远没有这样做。如果控件在没有任何反馈的情况下不接受输入,这也是非常令人沮丧的。让用户输入他们喜欢的任何内容,然后在您需要使用该值时进行验证。
-
解决问题的步骤: 1.) 处理
EN_CHANGE通知。每当用户采取可能更改文本的操作时都会发送它。 2.) 验证输入。这很简单:bool bValid = (swscanf(buf,L"%f",&f)==wcslen(buf));。 3.) 提供非侵入式反馈,例如更改控件的背景颜色,并禁用对话框的确定按钮。 -
感谢您迄今为止的建议。我计划稍后实施某种形式的通知,但现在我需要先解决输入验证。
-
@IInspectable 感谢您对 swscanf 和 EN_CHANGE 的提示
-
@IInspectable 嗯 ...我还没有太多时间彻底尝试,但似乎
EN_CHANGE没有被调用。我先检查了msg==WM_COMMAND,然后检查了HIWORD(wParam)==EN_CHANGE。但是当使用编辑控件时,我的内部测试输出不会被调用。知道有什么问题吗?我必须检查,但我认为我没有将编辑控件设置为ES_MULTILINE
标签: c++ validation winapi subclassing editcontrol