Установка точного размера клиентской области окна
Очередная тривиальная задача с нетривиальным решением и очередной пламенный привет разработчикам Windows. Начнем с задачи. Надо изменить размер окна таким образом, чтобы его клиентская область, то есть внутреннее содержимое без учета заголовка, рамок и полос прокрутки, стала четко заданной ширины и высоты. Создатели Windows, безусловно, позаботились о программистах, для решения этой задачи есть как минимум две функции - SetWindowPos и MoveWindow, все хорошо и замечательно, но... Как метко подметили в одном телесериале, все, что сказано до слова "но" - чушь собачья. Эти функции действительно выполняют свое предназначение, меняют размер окна, только применяют переданные им значения к внешней границе окна. При этом не учитываются ни визуальные темы, ни стили окна, ни наличие полос прокрутки, ни толщина рамки, короче, решения поставленной задачи "в лоб" дадут гарантированно неправильный результат.Размеры областей окна
К счастью, в Windows имеется вспомогательная функция AdjustWindowRectEx, которая используется как раз для подобных ситуаций. Он вычисляет фактические размеры окна, которые соответствуют заданным размерам его клиентской области. И вот здесь как раз учитываются стили, в том числе и расширенные, наличие у окна строки меню и установленная визуальная тема, но... Да-да, очередное "но". При расчете размеров никак не учитывается наличие в окне полос вертикальной и/или горизонтальной прокрутки. Они могут входить в размер клиентской области, а могут и не входить, в зависимости от задачи.
После обобщения всех исходных данных, у меня получилась вот такая универсальная функция. Она изменяет размер указанного окна под заданные размеры его клиентской области как с учетом полос прокрутки, так и без этого.
Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------------------------------
- ; Установить размеры окна с учетом точных размеров клиентской области
- ;------------------------------------------------------------------------
- ; hWnd - хэндл окна
- ; dWidth - ширина клиентской области
- ; dHeight - высота клиентской области
- ; dScroll - учитывать размеры полос прокрутки (1 = ДА, 0 = НЕТ)
- ;------------------------------------------------------------------------
- proc set_client_size hWnd:DWORD,dWidth:DWORD,dHeight:DWORD,dScroll:DWORD
- locals
- coord RECT
- endl
- pusha
- lea esi,[coord]
- ; Заполнить начальные размеры окна
- mov [esi+RECT.left],0
- mov [esi+RECT.top],0
- mov eax,[dWidth]
- mov [esi+RECT.right],eax
- mov eax,[dHeight]
- mov [esi+RECT.bottom],eax
- ; Учитывать полосы прокрутки?
- cmp [dScroll],1
- jne .no_scroll
- ; Получить стиль окна
- invoke GetWindowLong,[hWnd],GWL_STYLE
- mov ebx,eax
- ; Проверить наличие горизонтальной прокрутки
- test ebx,WS_HSCROLL
- jz @f
- invoke GetSystemMetrics,SM_CXHSCROLL
- add [esi+RECT.right],eax
- @@:
- ; Проверить наличие вертикальной прокрутки
- test ebx,WS_VSCROLL
- jz .no_scroll
- invoke GetSystemMetrics,SM_CYVSCROLL
- add [esi+RECT.bottom],eax
- .no_scroll:
- ; Подготовить данные для корректировки
- invoke GetWindowLong,[hWnd],GWL_EXSTYLE
- push eax
- ; Проверить наличие меню и его видимость
- invoke GetMenu,[hWnd]
- or eax,eax
- jz @f
- invoke GetMenuItemCount,eax
- or eax,eax
- jz @f
- mov eax,1
- @@:
- push eax
- invoke GetWindowLong,[hWnd],GWL_STYLE
- push eax
- ; Скорректировать размер окна
- invoke AdjustWindowRectEx,esi
- ; Установить новые размеры окна с учетом всего
- push SWP_NOZORDER+SWP_NOMOVE
- mov eax,[esi+RECT.bottom]
- sub eax,[esi+RECT.top]
- push eax
- mov eax,[esi+RECT.right]
- sub eax,[esi+RECT.left]
- push eax
- invoke SetWindowPos,[hWnd],NULL,NULL,NULL
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ; Установить точный размер окна без учета полос прокрутки
- stdcall set_client_size,[hwnddlg],500,200,0
- ...
- ...
- ; Установить точный размер окна с учетом полос прокрутки
- stdcall set_client_size,[hwnddlg],300,300,1
В приложении пример программы с исходным текстом, которая при нажатии на кнопку меняет размер своего окна с учетом клиентской области.
Просмотров: 925 | Комментариев: 2
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(23.06.2022 в 12:56):
Да, интересное замечание. Добавил, спасибо! Архив обновлен.
toor
(23.06.2022 в 12:25):
Меню может присутствовать, но быть невидно, например если у него нет ни одного элемента. С практической точки зрения это конечно ерунда (зачем делать меню без элементов?), но чисто технически такое может быть. Чтобы процедура работала точнее, проверку наличия меню лучше выполнять так:
b := (GetMenu(Handle) > 0) and (GetMenuItemCount(GetMenu(Handle)) > 0)
b := (GetMenu(Handle) > 0) and (GetMenuItemCount(GetMenu(Handle)) > 0)
Добавить комментарий
Заполните форму для добавления комментария