Blog. Just Blog

Графический курсор (каретка) в поле EDIT

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Сегодня отдохнем от системы и немного поработаем с графикой, будем делать собственный графический курсор в поле EDIT. Какого-то необычайно полезного практического применения этому нет, просто симпатичное дополнение к интерфейсу, например, к окнам нестандартной формы. Ну а что, раз уж наворотили чудо-окна, почему бы не наворотить и чудо-курсор.

Начнем с теории. В отличие от "мышиного" курсора, который может легко принимать любой вид, управлять кареткой, то есть курсором в текстовом поле, не так просто. Функция CreateCaret позволяет только описывать форму для каретки, но не меняет ее изображение. Достаточно один раз попробовать, чтобы убедиться в ее бесполезности. Придется самостоятельно рисовать графическую каретку на холсте поля ввода.
  1.         ; Загрузить из ресурсов картинку
  2.         invoke  GetModuleHandle,0
  3.         invoke  LoadBitmap,eax,1
  4.         mov     [hСaret],eax
  5.  
  6.         ; Выбрать картинку для холста поля ввода
  7.         invoke  GetDlgItem,[hwnddlg],ID_EDIT
  8.         invoke  GetDC,eax
  9.         mov     [hDC],eax
  10.         invoke  CreateCompatibleDC,[hDC]
  11.         mov     [hСaretDC],eax
  12.         invoke  SelectObject,[hСaretDC],[hСaret]
  13.  
  14.         ; Получить цвет угловой точки картинки
  15.         invoke  GetPixel,[hСaretDC],0,0
  16.         mov     [bColor],eax
  17.         ; Создать кисть с этим цветом
  18.         invoke  CreateSolidBrush,[bColor]
  19.         mov     [hBrush],eax
  20.  
  21.         ; Прибраться за собой
  22.         invoke  DeleteObject,[hСaret]
Для простоты реализации рисунок текстового курсора будет храниться в ресурсах. Загружаем его стандартными функциями, затем получаем холст поля ввода и добавляем к нему загруженный рисунок. Теоретически рисунок каретки может быть любого размера, но практически он должен хотя бы по вертикали соответствовать высоте поля ввода, а лучше высоте шрифта.

Тут есть одна проблема, которую мне не удалось решить. Дело в том, что даже если создать BMP с прозрачностью, то при его загрузке и наложении на форму все прозрачные места будут перекрашены в черный цвет. Поэтому приходится использовать картинку курсора, например, на белом фоне, а затем при создании окна назначать этот же фон полю ввода. Если найдете нормальный способ загрузки и отрисовки картинки с прозрачностью, то вся эта свистопляска с подгонкой фона поля ввода не понадобится. Чтобы хоть немного облегчить задачу, за фоновый цвет принимается угловая точка картинки курсора.
  1.         cmp     [msg],WM_CTLCOLOREDIT
  2.         je      .wm_color
  3.         ...
  4.         ...
  5. .wm_color:
  6.         ; Красный текст
  7.         invoke  SetTextColor,[wparam],0x000000FF
  8.         ; Подогнать фон под картинку
  9.         invoke  SetBkColor,[wparam],[bColor]
  10.  
  11.         ; Установить режим смешивания фоновых цветов
  12.         invoke  SetBkMode,[wparam],OPAQUE
  13.         ; Фоновая кисть
  14.         mov     eax,[hBrush]
  15.         jmp     .finish
Когда главным окном будет получено сообщение об отрисовке фона поля ввода, устанавливаем ранее созданную кисть цвета угловой точки рисунка каретки и цвет текста. В приведенном примере цвет текста фиксированный - красный.

Поскольку основная работа происходит непосредственно в пределах поля ввода, его обработчик придется субклассировать. Из-за ограничений в реализации графическая каретка должна работать по терминальному принципу, то есть она всегда находится после текста, а новые символы добавляются только в конец строки. Именно это и надо оформить в субклассированном обработчике. При получении сообщения о нажатии клавиши каретка принудительно переводится в конец поля ввода, а только потом обрабатывается само нажатие. Там же при наступлении различных событий штатная каретка скрывается при помощи функции HideCaret, а часть сообщений вообще подавляются, чтобы не допустить установку каретки в середину текста. Кроме перечисленных действий, в поле ввода блокируется автовыделение текста при перемещении по форме клавишей табуляции.
  1. ;------------------------------------------------
  2. ; Субклассированный обработчик
  3. ;------------------------------------------------
  4. proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
  5.         cmp     [uMsg],WM_GETDLGCODE
  6.         je      .getdlgcode
  7.         cmp     [uMsg],WM_CHAR
  8.         je      .wm_char
  9.         cmp     [uMsg],WM_PAINT
  10.         je      .wm_paint
  11.         cmp     [uMsg],WM_SETFOCUS
  12.         je      .wm_paint
  13.         cmp     [uMsg],WM_LBUTTONDOWN
  14.         je      .cancel
  15.         cmp     [uMsg],WM_LBUTTONDBLCLK
  16.         je      .cancel
  17.         cmp     [uMsg],WM_KEYDOWN
  18.         je      .cancel
  19. .char_ok:
  20.         ; Передать управление предыдущему обработчику или пропустить
  21.         ; разрешенный символ
  22.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  23.         ret
  24. .cancel:
  25.         ; Спрятать курсор
  26.         invoke  HideCaret,[hEdit]
  27.         ; Подавить сообщение
  28.         xor     eax,eax
  29.         ret
  30.  
  31. .wm_paint:
  32.         ; Курсор в конец текста
  33.         invoke  SendMessage,[hEdit],WM_GETTEXTLENGTH,0,0
  34.         invoke  SendMessage,[hEdit],EM_SETSEL,eax,eax
  35.  
  36.         ; Спрятать курсор
  37.         invoke  HideCaret,[hEdit]
  38.         jmp     .char_ok
  39.  
  40. .wm_char:
  41.         ; Курсор в конец текста
  42.         invoke  SendMessage,[hEdit],WM_GETTEXTLENGTH,0,0
  43.         invoke  SendMessage,[hEdit],EM_SETSEL,eax,eax
  44.  
  45.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  46.  
  47.         ; Перерисовать содержимое окна
  48.         invoke  InvalidateRect,[hEdit],0,TRUE
  49.         invoke  UpdateWindow,[hEdit]
  50.         ret
  51.  
  52. .getdlgcode:
  53.         ; Спрятать курсор
  54.         invoke  HideCaret,[hEdit]
  55.  
  56.         ; Передать управление предыдущему обработчику
  57.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  58.  
  59.         ; Подавить в ответе флаг DLGC_HASSETSEL
  60.         and     eax,NOT DLGC_HASSETSEL
  61.         ret
  62. endp
Далее по таймеру с помощью функции GetCaretPos получаем координаты каретки в пределах рабочего окна и по этим координатам накладываем на холст поля ввода картинку нашего красивого курсора. Небольшой сдвиг вправо нужен, чтобы курсор не наползал слишком близко на текст.
  1. .wmtimer:
  2.         ; Получить координаты каретки
  3.         invoke  GetCaretPos,CaretPos
  4.         ; Немного сдвинуть вправо
  5.         add     [CaretPos.x],1
  6.         ; Нарисовать картинку сердечка
  7.         invoke  BitBlt,[hDC],[CaretPos.x],[CaretPos.y],32,32,\
  8.                 [hСaretDC],0,0,SRCCOPY
После каждого нажатия клавиши поле ввода перерисовывается, тем самым решается вопрос с отрисовкой каретки на новой позиции. Еще желательно установить ограничение на количество символов в поле ввода, чтобы каретка не выходила за его границы. Оно не смертельно и вполне себе обрабатывается, просто смотрится некрасиво.

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

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

Custom.Caret.Demo.zip (5,239 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
==DJ==[ZLO] (17.09.2021 в 08:48):
Это на 1o-ke:
https://www.mediafire.com/file...7_083555.mp4
-upd
на 7-ke тоже самое. Вот только при записи заметил, что он не постоянно мигает, а только шесть раз.
ManHunter (15.09.2021 в 22:45):
Не смог воспроизвести ситуацию с кареткой, я вроде предусмотрел ее подавление в разных ситуациях.
==DJ==[ZLO] (14.09.2021 в 08:18):
==DJ==[ZLO] (13.09.2021 в 21:56):
Что-то похожее видел в кейгенах.

[Дело в том, что даже если создать BMP с прозрачностью, то при его загрузке и наложении на форму все прозрачные места будут перекрашены в черный цвет.]
- А с пнг такое не прокатит?

Заметил штуку: (Win7) При запуске customcaret в системной панели перейти на другое приложение и вернуться щелкнув customcaret появляется каретка | возле сердечка и остаётся мигать пока не нажмешь на edit.
wet (12.08.2021 в 20:55):
Проблема с индикатором раскладки решается гораздо проще. Как известно в поле ввода системный курсор мыши принимает вид OCR_IBEAM - I-образный курсор.
Всё что нам нужно, это заменять безликий I-образный курсор на свой красивый, с флагом страны например. Мониторить GetKeyboardLayout на предмет раскладки, и ставить свои курсоры SetSystemCursor. Курсоры брать из файла ресурсов, как вариант. Программа на несколько строк.
ManHunter (09.08.2021 в 10:32):
Кстати, да, отличный пример с раскладкой.
rnd (09.08.2021 в 07:05):
Ну, практическое применение графическому курсору есть, правда почему-то большинство разработчиков игнорируют этот запрос, даже создатели ОСей.

Логично предположить, коль наше внимание уперлось в курсорное поле, то мы ожидаем там увидеть не только само поле и текст с курсором, но и... правильно - раскладку клавиатуры, дабы не стрелять глазами на панель - какой же там язык сейчас на раскладке (?)

Неплохо в этом смысле организована программа Curlit, хотя есть и другие в том числе и платные, увы. Когда мы смотрим на курсор - то лучше видеть сразу информацию о раскладке (флаг языка, например), и это освобождает наше внимание от поиска переключения раскладки на панели, которая имеет свойство ещё и сворачиваться...

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

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

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