API и FreeBasic. (позиционирование и размеры окна)
В одной из прошлых статей изменяя стили, мы познакомились с функцией SetWindowPos. Ничто не мешат применить эту функцию для изменения размеров и расположения окна. И так пример с использованием SetWindowPos:
#INCLUDE "windows.bi" Dim msg As MSG 'структурированная переменная MSG Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX Dim As RECT FWRECT ' структура Rect для определения размеров рабочего стола Dim As String NameClass="MyClass" ' переменная имени класса Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля Dim Shared As Integer Dwidth 'ширина рабочего стола ' функция класса Function wndproc(hwnd As HWND, msg As Uinteger,_ wparam As WPARAM, lparam As LPARAM) As Integer Static width_ As Integer=300 Select Case msg Case WM_DESTROY PostQuitMessage(0) Case WM_MOUSEWHEEL Dim As Long wp = wparam 'делаем значение со знаком If wp<0 Then width_+=1 Else width_-=1 Endif 'изменяем размеры окна SetWindowPos(hwnd,0,0,0,width_,width_,SWP_NOMOVE Or SWP_NOZORDER) Case WM_LBUTTONDOWN 'Установка окна в верхний левый угол SetWindowPos(hwnd,0,0,0,0,0,SWP_NOSIZE Or SWP_NOZORDER) Case WM_RBUTTONDOWN 'Установка окна в верхний правый угол SetWindowPos(hwnd,0,Dwidth-width_,0,0,0,SWP_NOSIZE Or SWP_NOZORDER) End Select Return DefWindowProc(hwnd,msg,wparam,lparam) End Function ' получаем хендл рабочего стола Var win=GetDesktopWindow() ' получаем размеры рабочего стола в структуру GetWindowRect(win,@FWRECT) ' заносим ширину рабочего стола в переменную Dwidth = FWRECT.right ' Заполнение структуры WNDCLASSEX With wc .cbSize=SizeOf(WNDCLASSEX) .style=CS_HREDRAW Or CS_VREDRAW .lpfnWndProc=@wndproc .hInstance=Hinst .hIcon=LoadIcon(0,IDI_QUESTION) .hCursor=LoadCursor(0,IDC_HELP) .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME) .lpszClassName=StrPtr(NameClass) .hIconSm=.hIcon End With ' Регистрация класса окна If RegisterClassEx(@wc)=0 Then Print "Register error, press any key" Sleep End Endif 'Создание окна CreateWindowEx(0,NameClass,"Первое окно",_ WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,300,300,0,0,Hinst,0) ' Цикл сообщений While GetMessage(@msg,0,0,0) TranslateMessage(@msg) DispatchMessage(@msg) Wend
В данном примере по нажатию правой кнопки мыши, окно перемещается в правый угол. По нажатию левой кнопки мыши в левый угол. А если покрутить колесико мыши, то окно изменяет свои размеры в соответствии с направлением.
В этом примере появилось кое-что новое. И я попробую объяснить это. В первую очередь появилась структурированная переменная FWRECT, имеющая тип RECT (ее поля):
- left
- top
- right
- bottom
Все они имеют тип Long. Очень много функций используют в своем параметре эту структуру. И функция GetWindowRect одна из них. Ее параметры:
- HWND -хендл окна для определения его характеристик
- RECT - структура типа RECT
В результате работы функции GetWindowRect в поля структуры запишется расположение (x,y -верхний левый угол) и значение по осям X и Y от верхнего левого угла (right , bottom) . Но перед тем как определить размеры рабочего стола , нужно получить его хендл. В этом поможет функция GetDesktopWindow(). Определив хендл, а потом характеристики окна, нам нужно всего одно из полей структуры (right). Это даст нам ширину окна, ведь ширина окна вычисляется так (right-left) , но поскольку параметр Left у рабочего стола всегда нулевой, то вычислять нет надобности. Получив ширину, заносим значение в глобальную переменную для позиционирования окна в правом углу рабочего стола. Как вы понимаете, для того чтобы наше окошко было в рамках рабочего стола и примыкало к правой его границе, нам нужно вычесть из общей ширины окна рабочего стола ширину нашего окошка. Это и будет координата по оси X для правого позиционирования. Для левого позиционирования окна ничего вычислять не надо, координаты рабочего стола и нашего окна в этом случае совпадают.(0,0).
В нашей функции сообщений для всех трех случаев используется функция SetWindowPos. Для изменения размеров окна используются 5 и 6 параметры и флаги SWP_NOMOVE Or SWP_NOZORDER, говорящие системе, что нужно игнорировать параметры перемещения и стиля окна. Сообщение WM_MOUSEWHEEL определяет движение колесика мыши и в параметр WPARAM заносит числовое значение, которое характеризует движение в ту или иную сторону. Положительное значение указывает, что колесо было повернуто вперед, в сторону от пользователя; отрицательное значение указывает, что колесо было повернуто назад, в сторону пользователя. Однако значение в параметре WPARAM базируется на типе UINTEGER (беззнаковое) , Именно поэтому мы создали переменную WP с типом Integer и присваиваем ему значение WPARAM.
Для изменения расположения используются параметры 3 и 4, а так же флаги SWP_NOSIZE Or SWP_NOZORDER , говорящие системе, что нужно игнорировать параметры изменения размеров и стиля окна. При нажатии левой кнопкой мыши, мы в параметры заносим (0,0) . При нажатии правой кнопкой мыши (Dwidth-width_ , 0)
Все таки великолепная функция SetWindowPos!
Как бы там не было, но для изменения размеров и расположения чаще применяют функцию MoveWindow, ее параметры:
- hWnd - хендл окна
- X - расположение по оси Х
- Y - расположение по оси Y
- nWidth - ширина окна
- nHeight - высота окна
- bRepaint - флаг перерисовки клиентской области (если 1 - то перерисовать , если 0 не перерисовывать)
Я считаю что объяснять по этой функции ничего не нужно, все и так интуитивно понятно. Поэтому сразу пример:
#INCLUDE "windows.bi" 'Создание структурированной переменной MSG Dim msg As MSG 'Создание окна Var hwnd=CreateWindowEx(0,"#32770","Первое окно",WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,300,300,0,0,0,0) MoveWindow(hwnd,0,0,640,480,TRUE) 'Обработка сообщений в цикле While GetMessage(@msg,0,0,0) DispatchMessage(@msg) If msg.message=WM_COMMAND Then Exit While Wend
Я для примера взял самый маленький исходный текст создания окошка из нашей первой статьи. Здесь изначально создается окно с размерами 300х300 и в координатах 100,100. Далее с помощью MoveWindow мы меняем характеристики диалогового окна.
Иногда требуется выставить размеры окна и ограничить их по высоте и ширине. То есть окно должно иметь свойство менять размеры, но в определенных рамках. Скажем не больше 500 и не меньше 200 по ширине и высоте. Давайте это реализуем.
Делается это с помощью отлавливания сообщения WM_GETMINMAXINFO , которое вынимает из параметра Lparam адрес структуры MINMAXINFO. В зависимости от того, что мы занесем в эту структуру, таковы и будут характеристики окна. После того, как сообщение будет обработано, нужно возвратить ноль.И так по порядку:
Структура MINMAXINFO (точнее ее поля):
- ptReserved - не испольуется
- ptMaxSize - устанавливает развернутую ширину (point.x) и развернутую высоту (point.y) окна
- ptMaxPosition - устанавливает позицию левой стороны развернутого окна (point.x) и позицию верхней части развернутого окна (point.y)
- ptMinTrackSize - определяет минимум устанавливаемой ширины (point.x) и минимум устанавливаемой высоты (point.y) окна.
- ptMaxTrackSize - определяет максимум устанавливаемой ширины (point.x) и максимум устанавливаемой высоты (point.y) окна
Все поля структуры MINMAXINFO имеют тип структуры POINT (ее поля):
- X - координата х
- Y - координата y
Вы наверно уже догадались, что для нашей задачи потребуются два поля структуры MINMAXINFO (ptMinTrackSize и ptMaxTrackSize). В эти поля и надо прописать наши значения. И так пример:
#INCLUDE "windows.bi" Dim msg As MSG 'структурированная переменная MSG Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX Dim Shared As MINMAXINFO Ptr minmax ' структура для определения рамок размеров Dim As String NameClass="MyClass" ' переменная имени класса Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля ' функция класса Function wndproc(hwnd As HWND, msg As Uinteger,_ wparam As WPARAM, lparam As LPARAM) As Integer Static width_ As Integer=300 Select Case msg Case WM_DESTROY PostQuitMessage(0) Case WM_GETMINMAXINFO minmax=Cast(MINMAXINFO Ptr,lparam) minmax->ptMinTrackSize.x=200 'минимальный размер по оси X minmax->ptMinTrackSize.y=200 'минимальный размер по оси Y minmax->ptMaxTrackSize.x=500 'максимальный размер по оси X minmax->ptMaxTrackSize.y=500 'максимальный размер по оси Y Return 0 End Select Return DefWindowProc(hwnd,msg,wparam,lparam) End Function ' Заполнение структуры WNDCLASSEX With wc .cbSize=SizeOf(WNDCLASSEX) .style=CS_HREDRAW Or CS_VREDRAW .lpfnWndProc=@wndproc .hInstance=Hinst .hIcon=LoadIcon(0,IDI_QUESTION) .hCursor=LoadCursor(0,IDC_HELP) .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME) .lpszClassName=StrPtr(NameClass) .hIconSm=.hIcon End With ' Регистрация класса окна If RegisterClassEx(@wc)=0 Then Print "Register error, press any key" Sleep End Endif 'Создание окна CreateWindowEx(0,NameClass,"Первое окно",_ WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,300,300,0,0,Hinst,0) ' Цикл сообщений While GetMessage(@msg,0,0,0) TranslateMessage(@msg) DispatchMessage(@msg) Wend
Как видите мы отловили сообщение WM_GETMINMAXINFO , вынули адрес из LPARAM и занесли этот адрес в заранее объявленную структурированную переменную minmax. Далее в каждое из полей структуры прописали нужные значения и вернули 0 как и прописано по спецификации к этому сообщению. Аналогичным образом можно установить значения в остальные поля структуры.
На этом все, всего доброго!
содержание | назад | вперед