Blog. Just Blog

Блокировка автовыделения текста в поле EDIT

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
При создании диалогового окна, а также при перемещении по его элементам клавишей табуляции, текст в полях типа EDIT автоматически выделяется. Это стандартное поведение системы, так предусмотрено разработчиками Windows. Интересный вопрос, почему сделано именно так. Может быть самому Биллу Гейтсу было лениво нажимать кнопки Ctrl+A перед копированием текста из форм, может быть еще что-то, ответа я не знаю. Но зато у меня есть ответ на другой вопрос: можно ли сделать так, чтобы текст в поле EDIT автоматически не выделялся?

Перед тем, как принять решение о (не)выделении текста в поле EDIT, система посылает элементу диалогового окна сообщение WM_GETDLGCODE, которое должно вернуть соответствующий набор флагов. Так вот, если в ответе взведен флаг DLGC_HASSETSEL, то текст выделяется. Несложно догадаться, что по умолчанию этот флаг взводится всегда. При этом сообщение WM_GETDLGCODE самим диалоговым окном никак не обрабатывается, так что нужно воспользоваться уже известным нам субклассированием. Будь то разовое для конкретного поля или универсальное субклассирование, не важно.
  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.         ...
Важно то, что при поступлении элементу диалогового окна сообщения WM_GETDLGCODE, в итоговом ответе системе мы должны подавить флаг DLGC_HASSETSEL.

Делается это очень просто. В субклассированном обработчике элемента диалогового окна ловим сообщение WM_GETDLGCODE, отправляем запрос дальше по цепочке через CallWindowProc, но в полученном ответе сбрасываем соответствующий флаг DLGC_HASSETSEL:
  1. proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
  2.         ; Пришло сообщение WM_GETDLGCODE?
  3.         cmp     [uMsg],WM_GETDLGCODE
  4.         je      .getdlgcode
  5.         ...
  6. .getdlgcode:
  7.         ; Передать управление предыдущему обработчику
  8.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  9.         ; Подавить в ответе флаг DLGC_HASSETSEL
  10.         and     eax,NOT DLGC_HASSETSEL
  11.         ret
Теперь при первоначальной прорисовке диалогового окна или при путешествии по элементам окна при помощи табуляции, текст в субклассированном поле ввода выделен не будет. Цель достигнута.

Но раз уж речь коснулась сообщения сообщения WM_GETDLGCODE и сопутствующих флагов, то давайте еще разберем флаг DLGC_WANTMESSAGE. На секунду отвлечемся. Как известно, если в диалоговом окне нажать клавишу Esc, то окну будет отправлено сообщение WM_CLOSE, неважно, был ли в это время активен какой-нибудь из его элементов или было активно само окно. Возвращаемся к теме. Перед тем, как отправить сообщение WM_CLOSE главному обработчику диалогового окна, система интересуется, а нет ли у активного элемента диалогового окна желания как-то прореагировать на нажатие кнопки Esc? Опять же, как несложно догадаться, при стандартном поведении означенных элементов, такого желания у них возникать не должно. По умолчанию флаг DLGC_WANTMESSAGE возвращается сброшенным, но раз уж мы субклассировали обработчик элемента, то почему бы не обработать и этот флаг? Отрабатываем сообщение, как показано выше, затем для ответа взводим флаг DLGC_WANTMESSAGE. Таким образом главный обработчик диалогового окна никогда не узнает о том, что от него хотела система.
  1. ;------------------------------------------------
  2. ; Субклассированный обработчик
  3. ;------------------------------------------------
  4. proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
  5.         cmp     [uMsg],WM_GETDLGCODE
  6.         je      .getdlgcode
  7. .char_ok:
  8.         ; Передать управление предыдущему обработчику или пропустить
  9.         ; разрешенный символ
  10.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  11.         ret
  12. .getdlgcode:
  13.         ; Передать управление предыдущему обработчику
  14.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  15.  
  16.         ; Подавить в ответе флаг DLGC_HASSETSEL
  17.         and     eax,NOT DLGC_HASSETSEL
  18.  
  19.         ; Нажата клавиша Esc?
  20.         cmp     [wParam],27
  21.         jne     @f
  22.  
  23.         ; Очистить поле ввода
  24.         push    eax
  25.         invoke  SendMessage,[hEdit],WM_SETTEXT,0,0
  26.         pop     eax
  27.         ; Взвести в ответе флаг DLGC_WANTMESSAGE
  28.         or      eax,DLGC_WANTMESSAGE
  29. @@:
  30.         ret
  31. endp
В то же время мы можем легко узнать, какую кнопку нажал пользователь и какую реакцию системы стоит ожидать. Скан-код нажатой клавиши передается в параметре сообщения wParam. Так, для клавиши табуляции он равен 9, для Esc - 27 и так далее. Реакция поля ввода при этом может быть соответствующей. Например, при табуляции делаем вид, что ничего не происходит и не взводим флаг, курсор при этом перемещается дальше. А вот при нажатии Esc очищаем поле ввода и не передаем управление главному обработчику окна. Другие действия зависят от поставленной задачи.

В приложении пример программы с исходным текстом, которая создает в диалоговом окне обычное и субклассированное поле ввода. Субклассированное поле подавляет автоматическое выделение текста, а по нажатию клавиши Esc очищает содержимое.

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

Subclassed.EDIT.Demo.zip (2,525 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 1095 | Комментариев: 2

Метки: Assembler
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (01.04.2020 в 11:29):
Так ведь никто же не заставляет так делать всегда. Но когда возникнет необходимость, тогда уже будет готовое решение.
user (01.04.2020 в 08:27):
Да чего там - реально удобно с этим автовыделением.
Тем более, что оно сбрасывается при первом же движении курсора.

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

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

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