Blog. Just Blog

Поле EDIT для ввода десятичных цифр

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Как известно, если элементу диалогового окна типа EDIT установить флаг ES_NUMBER, то ввести в него можно будет только символы из интервала "0" - "9". Это в теории. На практике же в это поле через Ctrl+V или контекстное меню совершенно спокойно можно вставить любые данные, о чем даже написано в официальной документации. А еще в это поле нельзя ввести отрицательное число. Таким образом, практическая ценность ES_NUMBER приближается к нулю. Давайте учтем все эти недостатки и сделаем собственное, правильное поле EDIT для ввода десятичных цифр.

Чтобы полностью контролировать ввод, надо будет воспользоваться субклассированием, заменив стандартную процедуру обработки на собственную. Это мы уже делали не раз, ничего нового тут нет.
  1. ; Сегмент данных
  2. section '.data' data readable writeable  
  3. OldProc dd ?    ; Адрес предыдущего обработчика
  4.  
  5. ; Сегмент кода
  6. section '.code' code readable executable
  7.         ...
  8.         ; Субклассирование на этапе инициализации окна
  9.         invoke  GetDlgItem,[hwnddlg],ID_SUB
  10.         ; Установить наш собственный обработчик
  11.         invoke  SetWindowLong,eax,GWL_WNDPROC,EditWindowProc
  12.         ; Сохранить хэндл предыдущего обработчика
  13.         mov     [OldProc],eax
  14.         ...
Для одиночного поля можно ограничиться этим решением, но если таких полей предполагается несколько, то лучше воспользоваться универсальным субклассированием.

Теперь переходим к самому обработчику. Он должен уметь следующее: фильтровать все символы, отличные от цифр; позволять вводить символ "минус", но не абы как, а только в первую позицию и только если там минуса еще нет; позволять копировать и вставлять данные с учетом упомянутых правил. Вот что у меня получилось:
  1. ;------------------------------------------------
  2. ; Субклассированный обработчик
  3. ;------------------------------------------------
  4. proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
  5.         locals
  6.                 tmp dd ?
  7.         endl
  8.  
  9.         ; Нажатие клавиши?
  10.         cmp     [uMsg],WM_CHAR
  11.         je      .chk_char
  12.         ; Вставка?
  13.         cmp     [uMsg],WM_PASTE
  14.         jne     .char_ok
  15. .loc_paste:
  16.         ; Получить формат буфера обмена
  17.         invoke  IsClipboardFormatAvailable,CF_TEXT
  18.         or      eax,eax
  19.         jz      .exit_proc
  20.  
  21.         ; Получить хэндл родительского окна
  22.         invoke  GetParent,[hEdit]
  23.         ; Открыть буфер обмена
  24.         invoke  OpenClipboard,eax
  25.         invoke  GetClipboardData,CF_TEXT
  26.         mov     ebx,eax
  27.         invoke  GlobalLock,eax
  28.  
  29.         ; Поочередно передать все символы из буфера обмена
  30.         mov     esi,eax
  31. @@:
  32.         lodsb
  33.         or      al,al
  34.         jz      @f
  35.         movzx   eax,al
  36.         invoke  SendMessage,[hEdit],WM_CHAR,eax,0
  37.         jmp     @b
  38. @@:
  39.         ; Закрыть буфер обмена
  40.         invoke  GlobalUnlock,ebx
  41.         invoke  CloseClipboard
  42.         jmp     .exit_proc
  43. .char_ok:
  44.         ; Передать управление предыдущему обработчику или пропустить
  45.         ; разрешенный символ
  46.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  47.         ret
  48. .chk_char:
  49.         ; Проверить код нажатой клавиши
  50.         mov     eax,[wParam]
  51.         cmp     al,VK_BACK      ; Backspace
  52.         je      .char_ok
  53.         cmp     al,22           ; Ctrl+V
  54.         je      .loc_paste
  55.         cmp     al,3            ; Ctrl+C
  56.         je      .char_ok
  57.         cmp     al,24           ; Ctrl+X
  58.         je      .char_ok
  59.  
  60.         cmp     al,'-'
  61.         jne     @f
  62.  
  63.         ; Позиция курсора на самом начале ввода?
  64.         lea     ebx,[tmp]
  65.         invoke  SendMessage,[hEdit],EM_GETSEL,ebx,NULL
  66.         cmp     dword [ebx],0
  67.         ; Нет, тут в любом случае минуса быть не может
  68.         jnz     .exit_proc
  69.  
  70.         ; Выделен фрагмент от самого начала или все поле целиком?
  71.         invoke  SendMessage,[hEdit],EM_GETSEL,NULL,ebx
  72.         cmp     dword [ebx],0
  73.         ; Да, существующий минус в любом случае перезапишется
  74.         jne     .char_ok
  75.  
  76.         ; Минус в самом начале уже есть?
  77.         invoke  SendMessage,[hEdit],WM_GETTEXT,2,ebx
  78.         cmp     byte [ebx],'-'
  79.         ; Нет, минус можно добавить
  80.         jne     .char_ok
  81.         ; Да, подавить ввод
  82.         jmp     .exit_proc
  83. @@:
  84.         cmp     al,'0'          ; Десятичная цифра?
  85.         jb      .exit_proc
  86.         cmp     al,'9'
  87.         jbe     .char_ok
  88. .exit_proc:
  89.         ; Подавить сообщение нажатия клавиши и вернуть из обработчика FALSE
  90.         xor     eax,eax
  91.         ret
  92. endp
Обработчик легко модифицировать под свои нужды, например, в своих программах я частенько использую клик колесиком мыши на поле ввода в качестве команды "вставить".

В приложении пример диалогового окна с двумя полями ввода. Одно имеет стандартный флаг ES_NUMBER, а второе использует субклассирование для корректного ввода десятичных цифр. Также в архиве есть небольшая программа Dec2Hex, которой я сам частенько пользуюсь. В ней на практике применяется субклассированный обработчик из этой статьи.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Dec.EDIT.Demo.zip (6,646 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 226 | Комментариев: 2

Метки: Assembler, окна

Комментарии

Отзывы посетителей сайта о статье
ManHunter (01.03.2020 в 16:34):
Василий, доработал и под такую ситуевину, спасибо! Архив и пример в статье обновлены.
Василий (01.03.2020 в 15:37):
Небольшой баг - если выделить число в edit'e и вставить отрицательное, а потом опять повторить, то минус теряется через раз

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2020
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0036 сек.) / Память: 5 Mb
Наверх