Blog. Just Blog

Быстрый поиск

Введите фрагмент названия статьи для поиска

Ограничение изменения размеров окна

10.06.2019 | Категория: Образ мышления: Assembler | Автор: ManHunter
Подавляющее большинство программ под Windows имеют окна, размер которых можно менять. Это хорошо и правильно, это основа концепции системы. Но в некоторых случаях надо сделать так, чтобы окно приложения нельзя было уменьшить дальше определенного размера, например, чтобы всегда была видна строка меню или чтобы гарантированно оставалось место для других элементов интерфейса. Также теоретически могут быть ограничения и на максимальный размер окна, хотя мне на ум не приходят ситуации, когда это нужно.

Ограничение изменения размера окна реализуется через обработку сообщения WM_SIZING, которое приходит главному окну при попытке изменить его размер путем перетаскивания границ или нажатия на кнопку разворачивания окна. В lparam сообщения передаются новые координаты окна, которые будут установлены после изменения его размера. Здесь можно проверить, не выходят ли они за допустимые границы и, в случае необходимости, скорректировать их до нужных значений.
  1. ; Обработчик сообщений окна
  2.         cmp     [msg],WM_SIZING
  3.         je      resize_window
  4. ...
  5. ...
  6. ...
  7. resize_window:
  8.         ; Минимальные и максимальные размеры окна
  9.         MAX_X = 400
  10.         MIN_X = 200
  11.  
  12.         MAX_Y = 250
  13.         MIN_Y = 80
  14.  
  15.         ; В регистре EDI указатель на структуру координат окна
  16.         mov     edi,[lparam]
  17.  
  18.         ; Проверить максимальную ширину
  19.         mov     edx,[edi+RECT.right]
  20.         sub     edx,[edi+RECT.left]
  21.         cmp     edx,MAX_X
  22.         jbe     @f
  23.         ; Установить максимальную ширину
  24.         mov     eax,[edi+RECT.left]
  25.         add     eax,MAX_X
  26.         mov     [edi+RECT.right],eax
  27. @@:
  28.         ; Проверить минимальную ширину
  29.         cmp     edx,MIN_X
  30.         jae     @f
  31.         ; Установить минимальную ширину
  32.         mov     eax,[edi+RECT.left]
  33.         add     eax,MIN_X
  34.         mov     [edi+RECT.right],eax
  35. @@:
  36.         ; Проверить максимальную высоту
  37.         mov     edx,[edi+RECT.bottom]
  38.         sub     edx,[edi+RECT.top]
  39.         cmp     edx,MAX_Y
  40.         jbe     @f
  41.         ; Установить максимальную высоту
  42.         mov     eax,[edi+RECT.top]
  43.         add     eax,MAX_Y
  44.         mov     [edi+RECT.bottom],eax
  45. @@:
  46.         ; Проверить минимальную высоту
  47.         cmp     edx,MIN_Y
  48.         jae     @f
  49.         ; Установить минимальную высоту
  50.         mov     eax,[edi+RECT.top]
  51.         add     eax,MIN_Y
  52.         mov     [edi+RECT.bottom],eax
  53. @@:
  54.         jmp     processed
Если нужно, то можно проверять, например, только изменение до минимального размера по ширине. В этом случае остальные проверки надо просто убрать.

Читать статью целиком »
Просмотров: 1188 | Комментариев: 2

Обработка перетаскивания ссылок в окно приложения

16.04.2019 | Категория: Образ мышления: Assembler | Автор: ManHunter

Обработка перетаскивания ссылок в окно приложения

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

Читать статью целиком »
Просмотров: 1372 | Комментариев: 0

Особенности работы с контролом SysMonthCal32

07.09.2018 | Категория: Образ мышления: Assembler | Автор: ManHunter

Различная ширина SysMonthCal32 в разных локалях

При разработке одной из своих программ я столкнулся с интересной ситуацией. Никаких ракетных технологий, просто в диалоговом окне выводится стандартный виджет календарика через контрол SysMonthCal32. Я работаю в русской версии Windows и наивно предположил, что размеры виджета календарика всегда должны как-то вписываться в те границы, которые я ему определил. Но, как вы можете видеть на этих скриншотах, ширина контрола с календариком заметно отличается в зависимости от установленной в системе локали, на что мне указал один из пользователей (Mufasa, спасибо!). Вариантов нет, пришлось изучить этот вопрос.

Читать статью целиком »
Просмотров: 1303 | Комментариев: 2

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

24.07.2018 | Категория: Образ мышления: 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
Чтобы не мелочиться, я сделал перетаскивание окна не только правой кнопкой мыши, но и колесиком. При комбинированном клике на окне одновременно и колесиком и правой кнопкой мыши, оно тоже будет перетаскиваться, но если отпустить одну из кнопок, то обработчик перемещения сбросится и перетаскивание остановится. Конечно, можно учесть и корректно обработать даже такую хитрую ситуацию, но я оставлю это вам.

Читать статью целиком »
Просмотров: 1334 | Комментариев: 0

Установка окна по центру с учетом нескольких мониторов

24.06.2018 | Категория: Образ мышления: Assembler | Автор: ManHunter
И вновь работа над ошибками. На этот раз переосмысление статьи об установке окна по центру экрана. Приведенный там код работает без проблем, но только для единственного монитора, при наличии двух и более мониторов результат получается неправильным. Основные принципы работы с несколькими мониторами я расписал в предыдущей статье, повторять не буду.
  1. ;-------------------------------------------------------------------------
  2. ; Процедура перемещения окна в центр экрана. Если окно развернуто или
  3. ; его размеры превышают размеры экрана, то окно не перемещается
  4. ; Параметры:
  5. ;   hwnd - хэндл окна
  6. ;   mode - относительно каких координат центровать окно (1 - только
  7. ;          рабочая область экрана с учетом размеров панели задач и
  8. ;          различных тулбаров, 0 - относительно размеров всего экрана)
  9. ;-------------------------------------------------------------------------
  10. proc    WindowToCenterEx hwnd:DWORD, mode:DWORD
  11.  
  12.         MONITOR_DEFAULTTONEAREST = 2
  13.  
  14.         struct MONITORINFO
  15.           cbSize    dd ?
  16.           rcMonitor RECT
  17.           rcWork    RECT
  18.           dwFlags   dd ?
  19.         ends
  20.  
  21.         locals
  22.           minfo MONITORINFO
  23.           coord RECT
  24.         endl
  25.  
  26.         ; Сохранить все регистры
  27.         pusha
  28.  
  29.         ; Такое окно существует?
  30.         invoke  IsWindow,[hwnd]
  31.         or      eax,eax
  32.         jz      .loc_ret
  33.         ; Окно развернуто на весь экран?
  34.         invoke  IsZoomed,[hwnd]
  35.         or      eax,eax
  36.         jnz     .loc_ret
  37.  
  38.         ; Получить размеры окна
  39.         lea     eax,[coord]
  40.         invoke  GetWindowRect,[hwnd],eax
  41.  
  42.         ; Монитор, на котором находится окно
  43.         invoke  MonitorFromWindow,[hwnd],MONITOR_DEFAULTTONEAREST
  44.  
  45.         ; В регистре ESI указатель на структуру информации о мониторе
  46.         lea     esi,[minfo]
  47.         mov     [esi+MONITORINFO.cbSize],sizeof.MONITORINFO
  48.         invoke  GetMonitorInfo,eax,esi
  49.  
  50.         ; Весь экран
  51.         lea     esi,[minfo.rcMonitor]
  52.         cmp     [mode],0
  53.         je      @f
  54.         ; Рабочая область экрана
  55.         lea     esi,[minfo.rcWork]
  56. @@:
  57.         mov     eax,[esi+RECT.right]
  58.         sub     eax,[esi+RECT.left]
  59.  
  60.         lea     edi,[coord]
  61.         mov     ebx,[edi+RECT.right]
  62.         sub     ebx,[edi+RECT.left]
  63.  
  64.         ; Окно шире монитора
  65.         cmp     ebx,eax
  66.         jg      .loc_ret
  67.  
  68.         mov     ecx,[esi+RECT.bottom]
  69.         sub     ecx,[esi+RECT.top]
  70.  
  71.         mov     edx,[edi+RECT.bottom]
  72.         sub     edx,[edi+RECT.top]
  73.  
  74.         ; Окно выше монитора
  75.         cmp     edx,ecx
  76.         jg      .loc_ret
  77.  
  78.         shr     ebx,1
  79.         shr     eax,1
  80.         add     eax,[esi+RECT.left]
  81.         sub     eax,ebx
  82.  
  83.         shr     edx,1
  84.         shr     ecx,1
  85.         add     ecx,[esi+RECT.top]
  86.         sub     ecx,edx
  87.  
  88.         ; Разместить окно по центру монитора
  89.         invoke  SetWindowPos,[hwnd],NULL,eax,ecx,NULL,NULL,\
  90.                 SWP_NOSIZE+SWP_NOZORDER
  91.  
  92. .loc_ret:
  93.         ; Восстановить все регистры
  94.         popa
  95.         ret
  96. endp
Параметры вызова точно такие же, как и у старой функции: hwnd - хэндл окна, которое надо отцентровать, mode - режим центровки: 0 - установить окно по центру всего экрана, 1 - установить окно по центру рабочей области, то есть с учетом размеров панели задач и различных тулбаров.

Читать статью целиком »
Просмотров: 1395 | Комментариев: 5

Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2022
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.13 сек. / MySQL: 3 (0.057 сек.) / Память: 5 Mb
Наверх