Blog. Just Blog

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

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: 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 - установить окно по центру рабочей области, то есть с учетом размеров панели задач и различных тулбаров.

Теперь хотелось бы сказать несколько слов по поводу юзабилити. Почти всегда я пользовался одним монитором, лишь с недавнего времени на постоянку обзавелся вторым. И тут я понял, что меня дико раздражает практически во всем используемом софте. Несмотря на то, с каким монитором я работаю в данный момент, независимо от того, с какого монитора была запущена программа, все окна открываются на основном мониторе. Лично мне, например, было бы гораздо удобнее, чтобы новое окно программы появлялось именно на том мониторе, где сейчас у меня находится курсор. Реализуется это простейшим кодом:
  1. section '.data' data readable writeable
  2. ; Структура для получения координат курсора
  3. pt POINT
  4. ...
  5.  
  6. section '.code' code readable executable
  7.         ; Обработчик окна
  8.         ...
  9.         cmp     [msg],WM_INITDIALOG
  10.         je      wminitdialog
  11.         ...
  12.         ...
  13. wminitdialog:
  14.         ; Получить координаты курсора
  15.         invoke  GetCursorPos,pt
  16.         ; Переместить окно на монитор, где находится курсор
  17.         invoke  SetWindowPos,[hwnddlg],NULL,[pt.x],[pt.y],NULL,NULL,\
  18.                 SWP_NOSIZE+SWP_NOZORDER
  19.         ; Отцентровать окно
  20.         stdcall WindowToCenterEx,[hwnddlg],0
При инициализации диалогового окна получаем текущие координаты курсора, перемещаем окно по этим координатам, а затем центруем его относительно монитора, в котором эти координаты находятся. Простейший код, который экономит кучу времени и нервов. В своих программах я буду обязательно его применять, очень надеюсь, что другие разработчики тоже учтут этот момент. Давайте сделаем мир программного обеспечения чуть лучше :)

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

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

Advanced.Center.Window.Demo.zip (5,885 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 851 | Комментариев: 5

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

Комментарии

Отзывы посетителей сайта о статье
veeDAN (21.12.2018 в 14:39):
ManHunter, от Вас ничего.
ManHunter (25.11.2018 в 09:16):
- Вовочка, расскажи, как работает трансформатор?
- УУУУУууууууу-уууу-у-уу!

Весь код прокомментирован, статья на русском, пример прилагается. Что еще надо?
veeDAN (25.11.2018 в 03:15):
Подскажите, как это работает?
ManHunter (25.06.2018 в 07:41):
Да это понятно, мне и мышкой лишний раз махнуть - не переломлюсь. Просто когда работаешь с приятной и удобной программой, то мысленно посылаешь ее создателям лучи добра, а когда творится такая хрень, то в точности наоборот.
wet (25.06.2018 в 05:51):
ЦитатаТеперь хотелось бы сказать несколько слов по поводу юзабилити.

Можно запомнить одну комбинацию клавиш, которая экономит нервы и время по перетаскиванию окна:
Win+ Shift + стрелки вправо и влево и окно за один клик переносится из монитора в монитор

Так проще, чем ждать, пока программисты исправятся и начнут думать о нескольких мониторах :)

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

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

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