Blog. Just Blog

Тюнингуем контрол msctls_trackbar32

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
За время существования этого сайта тут было доработано уже несколько различных стандартных элементов управления, настало время провести тюнинг контрола msctls_trackbar32. Создается он обычным образом, например, через прописывание в ресурсах. Обязательно надо добавить в импорт библиотеку comctl32.dll и вызвать функцию InitCommonControls. Ну а поскольку мы будем добавлять к контролу различные нестандартные функции, то и делать это будем в специально отведенной процедуре-обработчике. Для этого воспользуемся субклассированием. Действия стандартные, примеров субклассирования на этом сайте предостаточно.
  1.         ; Настройки ползунка
  2.         invoke  GetDlgItem,[hwnddlg],IDC_PROGRESS
  3.         mov     [track],eax
  4.  
  5.         ; Установить наш собственный обработчик
  6.         invoke  SetWindowLong,[track],GWL_WNDPROC,TrackProc
  7.         ; Сохранить хэндл предыдущего обработчика
  8.         invoke  SetWindowLong,[track],GWL_USERDATA,eax
Теперь немного расскажу о расширенном функционале, который будет добавлен к ползунку. Во-первых, мне не нравится рамка, которая появляется при получении фокуса контролом. Конечно, это вроде как стандартное поведение, вроде так и должно быть, но мне все равно не нравится. Во-вторых, мне не нравится поведение ползунка при прокрутке контрола колесиком мыши. Лично я считаю, что поворот колесика мыши вперед должно увеличивать прогресс чего-либо, а поворот назад, соответственно, уменьшать. Стандартное же поведение ползунка ровно противоположное. Ну и третье, главное, что клик на полоске не переносит ползунок точно в эту позицию, а только сдвигает его на установленный шаг в указанном направлении.

Начинаем с избавления от рамки. Тут ничего нового, это уже было разобрано в одной из предыдущих статей. В случае с msctls_trackbar32 код в обработчике будет абсолютно такой же. Все необходимые значения констант и порядок установки обработчика можно посмотреть по приведенной ссылке.
  1.         ; Система хочет поменять состояние интерфейса
  2.         cmp     [uMsg],WM_UPDATEUISTATE
  3.         je      .wm_updateuistate
  4.         ...
  5.         ...
  6. .wm_updateuistate:
  7.         ; Принудительно сбросить фокус
  8.         mov     [wParam],(UIS_SET shl 16 + UISF_HIDEFOCUS)
  9.         jmp     .process_ok
Следующий косяк, который можно отремонтировать максимально быстро. При поступлении контролу уведомления о вращении колесика мыши надо просто инвертировать его направление и пробросить измененное уведомление оригинальному обработчику.
  1.         ; Вращение колесика мыши
  2.         cmp     [uMsg],WM_MOUSEWHEEL
  3.         je      .wm_mousewheel
  4.         ...
  5.         ...
  6. .wm_mousewheel:
  7.         ; Инвертировать направление вращения колесика
  8.         neg     [wParam]
  9.         jmp     .process_ok
Теперь самое интересное - обработка клика на полосе бегунка. Поскольку у нас используется субклассированный обработчик, событие сработает при клике внутри области контрола. Дальше логика следующая. Зная координаты места, куда кликнул пользователь, а также конечное значение бегунка, можно составить пропорцию и определить, какому значению из диапазона от начального до конечного соответствует эта точка. После этого надо будет просто установить позицию бегунка. Но, как говорится, "гладко было на бумаге". Проблема в том, что размеры всего контрола больше полосы бегунка, поэтому сопоставлять позицию клика надо не относительно размеров всего контрола, а только относительно полосы. Чтобы не хардкодить никаких поправочных значений, достаточно добавить на форму дополнительный элемент "рулетку". Это может быть STATIC, EDIT, да что угодно, главное, чтобы ширина и позиция этого элемента была в точности от первой риски шкалы до последней.

Добавляем "рулетку"
Добавляем "рулетку"

Для наглядности я сделал этот элемент видимым. В реальных проектах после позиционирования "рулетки" все риски на шкале можно убрать, а саму "рулетку" надо обязательно сделать невидимой. После всех выполненных манипуляций, при клике на контрол получаем координаты события при помощи функции GetMessagePos, затем при помощи функции ScreenToClient проецируем координаты клика на "рулетку". Остается, как я говорил выше, решить пропорцию и установить новую позицию бегунка в соответствии с местом клика. Важно проверять левую границу после пересчета координат, если она будет меньше начального значения, то надо принудительно приравнивать ее к этому значению.
  1.         ; Клик в области контрола
  2.         cmp     [uMsg],WM_LBUTTONDOWN
  3.         je      .wm_lbuttondown
  4.         ...
  5.         ...
  6. .wm_lbuttondown:
  7.         ; Получить координаты события клика
  8.         invoke  GetMessagePos
  9.         and     eax,0FFFFh
  10.         add     eax,5
  11.         mov     [pt.x],eax
  12.  
  13.         ; Пересчитать координаты в пределах линейки
  14.         invoke  ScreenToClient,[ruler],pt
  15.  
  16.         ; Начальная координата не должна выходить за границу линейки
  17.         mov     eax,[pt.x]
  18.         or      eax,eax
  19.         jns     @f
  20.         mov     [pt.x],0
  21. @@:
  22.         ; Получить размеры линейки
  23.         invoke  GetWindowRect,[ruler],coord
  24.  
  25.         ; Получить максимальное значение ползунка
  26.         invoke  SendMessage,[hBtn],TBM_GETRANGEMAX,NULL,NULL
  27.         xor     edx,edx
  28.         mov     ecx,[pt.x]
  29.         imul    ecx
  30.  
  31.         mov     ecx,[coord.right]
  32.         sub     ecx,[coord.left]
  33.         xor     edx,edx
  34.         idiv    ecx
  35.  
  36.         mov     ecx,[coord.right]
  37.         sub     ecx,[coord.left]
  38.         shr     ecx,1
  39.         cmp     ecx,edx
  40.         jbe     @f
  41.         inc     eax
  42. @@:
  43.         ; Установить новую позицию в соответствии с кликом
  44.         invoke  SendMessage,[hBtn],TBM_SETPOS, TRUE, eax
  45.         ; Отправить сообщение главному окну
  46.         invoke  SendMessage,[mainwnd],WM_HSCROLL,0,[hBtn]
  47.  
  48.         jmp     .process_ok
В приложении пример программы с исходным текстом, которая реализует два элемента управления msctls_trackbar32, один из которых стандартный, а второй тюнингованный.

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

msctls_trackbar32.Demo.zip (3,859 bytes)


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

Метки: Assembler

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

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

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

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