Поле EDIT для ввода десятичных цифр
Как известно, если элементу диалогового окна типа EDIT установить флаг ES_NUMBER, то ввести в него можно будет только символы из интервала "0" - "9". Это в теории. На практике же в это поле через Ctrl+V или контекстное меню совершенно спокойно можно вставить любые данные, о чем даже написано в официальной документации. А еще в это поле нельзя ввести отрицательное число. Таким образом, практическая ценность ES_NUMBER приближается к нулю. Давайте учтем все эти недостатки и сделаем собственное, правильное поле EDIT для ввода десятичных цифр.Чтобы полностью контролировать ввод, надо будет воспользоваться субклассированием, заменив стандартную процедуру обработки на собственную. Это мы уже делали не раз, ничего нового тут нет.
Code (Assembler) : Убрать нумерацию
- ; Сегмент данных
- section '.data' data readable writeable
- OldProc dd ? ; Адрес предыдущего обработчика
- ; Сегмент кода
- section '.code' code readable executable
- ...
- ; Субклассирование на этапе инициализации окна
- invoke GetDlgItem,[hwnddlg],ID_SUB
- ; Установить наш собственный обработчик
- invoke SetWindowLong,eax,GWL_WNDPROC,EditWindowProc
- ; Сохранить хэндл предыдущего обработчика
- mov [OldProc],eax
- ...
Теперь переходим к самому обработчику. Он должен уметь следующее: фильтровать все символы, отличные от цифр; позволять вводить символ "минус", но не абы как, а только в первую позицию и только если там минуса еще нет; позволять копировать и вставлять данные с учетом упомянутых правил. Вот что у меня получилось:
Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------
- ; Субклассированный обработчик
- ;------------------------------------------------
- proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
- locals
- tmp dd ?
- endl
- ; Нажатие клавиши?
- cmp [uMsg],WM_CHAR
- je .chk_char
- ; Вставка?
- cmp [uMsg],WM_PASTE
- jne .char_ok
- .loc_paste:
- ; Получить формат буфера обмена
- invoke IsClipboardFormatAvailable,CF_TEXT
- or eax,eax
- jz .exit_proc
- ; Получить хэндл родительского окна
- invoke GetParent,[hEdit]
- ; Открыть буфер обмена
- invoke OpenClipboard,eax
- invoke GetClipboardData,CF_TEXT
- mov ebx,eax
- invoke GlobalLock,eax
- ; Поочередно передать все символы из буфера обмена
- mov esi,eax
- @@:
- lodsb
- or al,al
- jz @f
- movzx eax,al
- invoke SendMessage,[hEdit],WM_CHAR,eax,0
- jmp @b
- @@:
- ; Закрыть буфер обмена
- invoke GlobalUnlock,ebx
- invoke CloseClipboard
- jmp .exit_proc
- .char_ok:
- ; Передать управление предыдущему обработчику или пропустить
- ; разрешенный символ
- invoke CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
- ret
- .chk_char:
- ; Проверить код нажатой клавиши
- mov eax,[wParam]
- cmp al,VK_BACK ; Backspace
- je .char_ok
- cmp al,22 ; Ctrl+V
- je .loc_paste
- cmp al,3 ; Ctrl+C
- je .char_ok
- cmp al,24 ; Ctrl+X
- je .char_ok
- cmp al,1 ; Ctrl+A
- je .char_ok
- cmp al,'-'
- jne @f
- ; Позиция курсора на самом начале ввода?
- lea ebx,[tmp]
- invoke SendMessage,[hEdit],EM_GETSEL,ebx,NULL
- cmp dword [ebx],0
- ; Нет, тут в любом случае минуса быть не может
- jnz .exit_proc
- ; Выделен фрагмент от самого начала или все поле целиком?
- invoke SendMessage,[hEdit],EM_GETSEL,NULL,ebx
- cmp dword [ebx],0
- ; Да, существующий минус в любом случае перезапишется
- jne .char_ok
- ; Минус в самом начале уже есть?
- invoke SendMessage,[hEdit],WM_GETTEXT,2,ebx
- cmp byte [ebx],'-'
- ; Нет, минус можно добавить
- jne .char_ok
- ; Да, подавить ввод
- jmp .exit_proc
- @@:
- cmp al,'0' ; Десятичная цифра?
- jb .exit_proc
- cmp al,'9'
- jbe .char_ok
- .exit_proc:
- ; Подавить сообщение нажатия клавиши и вернуть из обработчика FALSE
- xor eax,eax
- ret
- endp
В приложении пример диалогового окна с двумя полями ввода. Одно имеет стандартный флаг ES_NUMBER, а второе использует субклассирование для корректного ввода десятичных цифр. Также в архиве есть небольшая программа Dec2Hex, которой я сам частенько пользуюсь. В ней на практике применяется субклассированный обработчик из этой статьи.
Просмотров: 1277 | Комментариев: 13
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(04.09.2020 в 11:32):
GetDlgItemInt
Андрей
(04.09.2020 в 11:29):
Доброго дня. Вопросы не иссякли. Помимо ограничения по разрядности, решил прикрутить ограничение по максимально возможной вводимой цифре. К примеру мне нужно ввести байт в десятичном формате. Это три разряда в десятичной системе. Но по понятным причинам больше 255 вводится не должно. Так вот попытался воспользоваться функцией invoke GetDlgItemText,[hEdit],ID_SUB,buff_mes,32
Но она опять же не работает-) Хотя по логике вещей должна.
Ведь invoke SendMessage,[hEdit],WM_GETTEXTLENGTH,0,0 выдает наличие знаков которыми владеет окно с текущим хеделом. В чем моя ошибка?
Но она опять же не работает-) Хотя по логике вещей должна.
Ведь invoke SendMessage,[hEdit],WM_GETTEXTLENGTH,0,0 выдает наличие знаков которыми владеет окно с текущим хеделом. В чем моя ошибка?
Андрей
(03.09.2020 в 16:03):
Спасибо огромное!!!
ManHunter
(03.09.2020 в 15:57):
Андрей
(03.09.2020 в 15:48):
Я понимаю что задолбал своей простотой. Но если найдется время на ответ.
Соорудил в начале субобработчика следующую конструкцию.
invoke SendMessage, [hEdit], WM_GETTEXTLENGTH,0,0
cmp eax,6
ja .exit_proc ; 7 и более на выход
Но программа вообще перестала окно выводить. Судя по всему ей строчка с SendMessage в принципе не нравится. В чем моя ошибка?
Соорудил в начале субобработчика следующую конструкцию.
invoke SendMessage, [hEdit], WM_GETTEXTLENGTH,0,0
cmp eax,6
ja .exit_proc ; 7 и более на выход
Но программа вообще перестала окно выводить. Судя по всему ей строчка с SendMessage в принципе не нравится. В чем моя ошибка?
Андрей
(03.09.2020 в 11:52):
Пробовал таким образом в начале обработчика число символов добывать. Но почему то не взлетело.
;------------------------------------------------
; Субклассированный обработчик
;------------------------------------------------
proc EditWindowProcRun hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD invoke SetDlgItemText,[hwin],ID_SUB,buff_mes cmp eax,6 ja .exit_proc
Спасибо, буду пробовать.
;------------------------------------------------
; Субклассированный обработчик
;------------------------------------------------
proc EditWindowProcRun hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD invoke SetDlgItemText,[hwin],ID_SUB,buff_mes cmp eax,6 ja .exit_proc
Спасибо, буду пробовать.
ManHunter
(03.09.2020 в 11:34):
EM_SETLIMITTEXT, WM_GETTEXTLENGTH
Андрей
(03.09.2020 в 11:27):
И снова здравствуйте-)
Не работает подсказка, вернее работает, но совсем не так как хотелось.
Если контролировать число символов передаваемых из буфера обмена, то максимум чего можно добиться, это ограничение числа символов при разовой вставке копированием.
Однако это не спасает от того, что простым нажатием кнопки можно вставить 100500 знаков. Равно как и копированием, можно накидать столько же за несколько раз "вставить"
Не работает подсказка, вернее работает, но совсем не так как хотелось.
Если контролировать число символов передаваемых из буфера обмена, то максимум чего можно добиться, это ограничение числа символов при разовой вставке копированием.
Однако это не спасает от того, что простым нажатием кнопки можно вставить 100500 знаков. Равно как и копированием, можно накидать столько же за несколько раз "вставить"
Андрей
(28.07.2020 в 18:33):
Понял. Спасибо. Теперь думаю разберусь.
ManHunter
(28.07.2020 в 13:42):
Вот где код "Поочередно передать все символы из буфера обмена", там просто добавить счетчик вставляемых символов. Уже взяли из буфера, например, 10-15 или сколько там надо символов, значит все, стоп, остальное содержимое буфера обмена не обрабатываем.
А исходники я не выкладываю, если чего-то сразу нет в статьях в открытом доступе, значит этого нигде никогда и не появится.
А исходники я не выкладываю, если чего-то сразу нет в статьях в открытом доступе, значит этого нигде никогда и не появится.
Андрей
(28.07.2020 в 13:32):
Доброго дня.
Очень полезный пример. Сам я в winasm поскольку постольку, больше по микроконтроллерам кнопаю, на хобийном уровне. Но иногда приходится и в это дело вникать. Но изучение API дается туго. Из за отсутствия постоянной практики быстро всё улетает. Собственно данный пример мне очень подходит своей "защитой от дурака" в том плане что бы из поля ввода на компе загонять десятичные значения через com порт на микроконтроллер. Радует именн защита от дурака при копировании. Всяких hex и прочего по невнимательности.
Однако остался неосвещенным такой пунктик как ограничение числа вводимых знаков. Мне нужно с ограничением. И под это дело как нельзя лучше подходит Dec2Hex лежащий в исходниках. Нельзя ли исходный код оного увидеть. Или хотя бы кусок где реализован контроль числа вводимых знаков. Можно на мыло andrey_777@bk.ru
Если уж совсем нет, то в какую сторону смотреть реализацию. там API или ещё как. invoke SendDlgItemMessage,[hwnddlg],ID_SPD,EM_LIMITTEXT,3,0 я нашел. Но от вставки копированием 100500 знаков она увы не спасает.
Очень полезный пример. Сам я в winasm поскольку постольку, больше по микроконтроллерам кнопаю, на хобийном уровне. Но иногда приходится и в это дело вникать. Но изучение API дается туго. Из за отсутствия постоянной практики быстро всё улетает. Собственно данный пример мне очень подходит своей "защитой от дурака" в том плане что бы из поля ввода на компе загонять десятичные значения через com порт на микроконтроллер. Радует именн защита от дурака при копировании. Всяких hex и прочего по невнимательности.
Однако остался неосвещенным такой пунктик как ограничение числа вводимых знаков. Мне нужно с ограничением. И под это дело как нельзя лучше подходит Dec2Hex лежащий в исходниках. Нельзя ли исходный код оного увидеть. Или хотя бы кусок где реализован контроль числа вводимых знаков. Можно на мыло andrey_777@bk.ru
Если уж совсем нет, то в какую сторону смотреть реализацию. там API или ещё как. invoke SendDlgItemMessage,[hwnddlg],ID_SPD,EM_LIMITTEXT,3,0 я нашел. Но от вставки копированием 100500 знаков она увы не спасает.
ManHunter
(01.03.2020 в 16:34):
Василий, доработал и под такую ситуевину, спасибо! Архив и пример в статье обновлены.
Василий
(01.03.2020 в 15:37):
Небольшой баг - если выделить число в edit'e и вставить отрицательное, а потом опять повторить, то минус теряется через раз
Добавить комментарий
Заполните форму для добавления комментария