Blog. Just Blog

Перетаскивание окна за любое место правой кнопкой мыши

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
В одной из первых статей на этом блоге я рассказывал, как легко сделать перетаскивание окна за любое место левой кнопкой мыши. А тут что-то мне захотелось странного, а именно реализовать перетаскивание окна точно так же за любое место, но только правой кнопкой мыши. Как оказалось, простым пробросом сообщения от мышки на заголовок окна сделать это нельзя. После некоторых раздумий у меня получился вот такой вариант. При клике мышкой по окну оно захватывает события мыши при помощи функции SetCapture и сохраняет начальные координаты окна, при перемещении курсора принудительно перемещает окно вслед за ним, а при отпускании кнопки мышки освобождает перехват событий мыши функцией ReleaseCapture. Начнем с обработчика сообщений окна.
  1.         ; Установка обработчика перетаскивания правой кнопкой
  2.         ; мыши и колесиком
  3.         cmp     [msg],WM_RBUTTONDOWN
  4.         je      .drag_window_set
  5.         cmp     [msg],WM_MBUTTONDOWN
  6.         je      .drag_window_set
  7.  
  8.         ; Снятие обработчика перетаскивания правой кнопкой
  9.         ; мыши и колесиком
  10.         cmp     [msg],WM_RBUTTONUP
  11.         je      .drag_window_release
  12.         cmp     [msg],WM_MBUTTONUP
  13.         je      .drag_window_release
  14.  
  15.         ; Обработчик перемещения мыши
  16.         cmp     [msg],WM_MOUSEMOVE
  17.         je      .drag_window_ex
Чтобы не мелочиться, я сделал перетаскивание окна не только правой кнопкой мыши, но и колесиком. При комбинированном клике на окне одновременно и колесиком и правой кнопкой мыши, оно тоже будет перетаскиваться, но если отпустить одну из кнопок, то обработчик перемещения сбросится и перетаскивание остановится. Конечно, можно учесть и корректно обработать даже такую хитрую ситуацию, но я оставлю это вам.

Дальше нам понадобится определить несколько структур в сегменте данных, чтобы работать с координатами курсора и окна, а также с его размерами.
  1. pt  POINT
  2. pos POINT
  3. r   RECT
Ну и, собственно, сами обработчики. Как я уже писал выше, при клике колесиком или правой кнопкой мыши окно захватывает на себя все события мыши и запоминает свои начальные координаты. При перемещении мыши отслеживается текущее положение курсора и окно перемещается вслед за ним. При отпускании любой из нажатых кнопок окно освобождает захват событий мыши.
  1. .drag_window_set:
  2.         ; Запомнить положение окна и установить обработчик событий мыши
  3.         movsx   eax,word [lparam+0]
  4.         mov     [pos.x],eax
  5.         movsx   eax,word [lparam+2]
  6.         mov     [pos.y],eax
  7.  
  8.         invoke  SetCapture,[hwnddlg]
  9.  
  10. .drag_window_ex:
  11.         ; Обработчик установлен на наше окно?
  12.         invoke  GetCapture
  13.         cmp     eax,[hwnddlg]
  14.         jne     .processed
  15.  
  16.         ; Получить координаты курсора
  17.         invoke  GetCursorPos,pt
  18.         invoke  GetWindowRect,[hwnddlg],r
  19.  
  20.         ; Для окна без заголовка корректируем положение окна
  21.         ; с учетом толщины рамок, установленной в системе
  22.         mov     eax,[pos.x]
  23.         sub     [pt.x],eax
  24.         invoke  GetSystemMetrics,SM_CXFIXEDFRAME
  25.         shr     eax,1
  26.         sub     [pt.x],eax
  27.         mov     eax,[pos.y]
  28.         sub     [pt.y],eax
  29.         invoke  GetSystemMetrics,SM_CYFIXEDFRAME
  30.         shr     eax,1
  31.         sub     [pt.y],eax
  32.         mov     eax,[r.left]
  33.         sub     [r.right],eax
  34.         mov     eax,[r.top]
  35.         sub     [r.bottom],eax
  36.  
  37.         ; Переместить окно вслед за курсором
  38.         invoke  MoveWindow,[hwnddlg],[pt.x],[pt.y],[r.right],[r.bottom],TRUE
  39.         jmp     .processed
  40.  
  41. .drag_window_release:
  42.         ; Снять обработчик событий мыши
  43.         invoke  ReleaseCapture
  44.         jmp     .processed
Тут есть небольшая особенность. Дело в том, что функция GetWindowRect возвращает размеры модального окна без учета внешних рамок. Поэтому приходится дополнительно получать размеры вертикальных и горизонтальных рамок окна и корректировать положение окна с учетом этих значений.
  1.         ; Для окна с заголовком придется корректировать положение с учетом
  2.         ; толщины границ обрамления и высоты заголовка
  3.         mov     eax,[pos.x]
  4.         sub     [pt.x],eax
  5.         invoke  GetSystemMetrics,SM_CXFIXEDFRAME
  6.         sub     [pt.x],eax
  7.         mov     eax,[pos.y]
  8.         sub     [pt.y],eax
  9.         invoke  GetSystemMetrics,SM_CYFIXEDFRAME
  10.         sub     [pt.y],eax
  11.         invoke  GetSystemMetrics,SM_CYCAPTION
  12.         sub     [pt.y],eax
  13.         mov     eax,[r.left]
  14.         sub     [r.right],eax
  15.         mov     eax,[r.top]
  16.         sub     [r.bottom],eax
Но и это еще не все. Для окна с заголовком также приходится дополнительно корректировать положение с учетом высоты заголовка. Универсального способа, как при перетаскивании окна левой кнопкой мыши, здесь нет. Поэтому сперва вы определяетесь с типом окна, которое должно перетаскиваться, а затем выбираете тот или иной обработчик перемещения.

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

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

Advanced.Drag.Window.Demo.zip (5,276 bytes)


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

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

Комментарии

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

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

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

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