Проверка ввода элемента управления редактирования в подклассе для приема только чисел с плавающей запятой

В моем текущем проекте я боролся последние пару дней с подклассами редактирования полей. К настоящему времени я успешно создал подкласс для своего поля редактирования и проверил ввод так, чтобы он принимал только цифры, запятые, знак минус и команды клавиатуры.

Но на некоторое время я застрял в уточнении проверки ввода. Я хочу, чтобы мое поле редактирования действовало следующим образом:

  • принимать знак минус только на первой позиции
  • принять только один ведущий ноль
  • принять только одну запятую
  • запятая после нуля
  • управлять этими случаями при удалении отдельных символов или выделенных фрагментов текста с помощью «назад», «удалить», «выделить все» и затем вставить что-то поверх него

Мой код в его нынешней форме выглядит следующим образом и практически не содержит требований к расширенной проверке, которые я указывал выше:

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);
}

Любая идея о том, как алгоритмически решить эту проблему, очень ценится.

ОБНОВИТЬ

Благодаря предложениям Дэвида Хеффернана и 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;
}

Я, вероятно, добавлю еще визуальный отзыв для пользователя, но это сейчас не важно.

Однако на этот вопрос пока нет ответа. Мое намерение состояло в том, чтобы разрешить «,» как возможную десятичную точку.

3

Решение

Вам нужен конечный автомат. Сначала объявите свои штаты.

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

Когда пользователь вводит символ, вызывайте другую функцию проверки в зависимости от значения mState, используя блок переключателей.

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

Так, например, функция, которую вы вызываете, когда mState == NoCharacters, будет принимать любое число, десятичную точку или знак минуса.
Затем он изменил бы mState на MinusSign, если символ был знаком минус, LeadingZero, если это был ноль, и т. Д.

-1

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector