API и FreeBasic. (Окно)

В статье о диалоговом окне с классом #32770 были рассмотрены функции для создания диалогового окна и параметры этих функций. Конечно при всей простоте создания окна с помощью этого полезного класса, вы в первой же программе увидите несовершенство данного метода программирования. Во первых обработка сообщений в цикле не самый хороший вариант. Правильным и удобным вариантом является обработка сообщений в оконной процедуре.  Вы заметили, что у нас признаком закрытия окна служило сообщение WM_COMMAND, которое на самом деле должно использоваться совсем для других целей. Настоящим признаком закрытия окна (разрушения) в процедуре служит сообщение WM_DESTROY, которое недоступно в цикле. Далее при установке дочерних элементов, многие сообщения приходят в оконную процедуру, минуя цикл. То есть система сама вызывает оконную процедуру, передавая ей сообщения от ее дочерних элементов. И все же сообщения в цикле могут быть полезны хотя бы потому, что они глобальны для текущего потока и не зависят от окна (если не установить специально по другому). То есть вы можете отловить сообщения мыши и нажатия клавиатуры от всех окон, принадлежащих данному потоку. В ряде случаев это бывает полезно.

Большей гибкости в управлении окон можно достичь создав свой собственный класс.

Создание класса окна я бы разделил на три этапа:

  • Создание оконной процедуры
  • Заполнение структуры WNDCLASSEX
  • Регистрация класса

И так по порядку. Создание оконной процедуры ничем не отличается от создания обычной функции. Я не знаю почему во всех справочниках написано оконная процедура (и если честно не задавался этим). Ведь по сути нужно правильно называть "оконная функция". Ну да ладно называют процедурой, пусть будет процедурой. Она имеет четыре параметра:

  • hwnd - окно которому послано сообщение
  • msg - само сообщение
  • wparam - дополнительный параметр
  • lparam - дополнительный параметр

Кроме того следует заострить внимание на присутствие функции DefWindowProc в теле оконной процедуры, которая отсылает системе сообщения, которые мы не хотим обрабатывать. У нее такое же кол-во параметров и они единтичны с параметрами оконной процедуры.

Структура WNDCLASSEX (точнее ее поля):

  • cbSize -  размер этой структуры, в байтах
  • style - стиль(и) класса
  • lpfnWndProc - указатель на процедуру окна
  • cbClsExtra - объем памяти выделяемый за структурой класса.
  • cbWndExtra - объем дополнительной памяти за экземпляром окна.
  • hInstance - хендл текущего модуля
  • hIcon - хендл иконки (отображается в заголовке окна)
  • hCursor - хендл курсора
  • hbrBackground - кисть для закрашивания фона (цвет клиентской части окна)
  • lpszMenuName - указатель на строку с именем меню из ресурсов
  • lpszClassName - указатель на строку с именем класса
  • hIconSm - хендл маленькой иконки(отображается в панели задач)

Полей не мало, но заполнять можно не все (для разных задач).  Обязательные для заполнения  поля:

  • cbSize -  размер этой структуры, в байтах
  • lpfnWndProc - указатель на процедуру окна
  • lpszClassName - указатель на строку с именем класса

Что касается регистрации класса, то этим заведует функция RegisterClassEx с одним единственным параметром: адрес структурированной переменной WNDCLASSEX . Если при создании используется структура WNDCLASS вместо расширенной WNDCLASSEX , то регистрацию следует проводить функцией RegisterClass. В остальном все тоже самое. Если функция вернет ноль, то регистрация неудачна.

А теперь пример:

#INCLUDE "windows.bi"
Dim msg As MSG 'структурированная переменная MSG
Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX
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 Select Case msg Case WM_DESTROY PostQuitMessage(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


Я поясню некоторые моменты.

Функция GetModuleHandle возвращает хендл модуля. Если вместо нуля в параметре передать имя модуля , то функция вернет его хендл. Но в нашем случае мы передали ноль, поэтому она возвращает текущий модуль.

Функция PostQuitMessage указывает системе, что поток сделал запрос на то, чтобы завершить свою работу. Ее единственный параметр: код завершения (чаще всего ставят ноль, но может быть любое число). Вызов данной функции заставляет функцию GetMessage возвратить ноль, что приводит к выходу из цикла и завершению программы.

Функции LoadIcon и LoadCursor загружают иконку и курсор соответственно. У этих функций мы в первом параметре передали 0, это дает возможность загружать иконку или курсор из стандартных, предоставлямых системой иконок или курсоров. Если в первом параметре передать хендл приложения, то во втором параметре можно передать строку имени ресурса иконки или курсора.

Поле структуры style заполнено константами, которые говорят системе, чтобы та обновляла клиентскую часть окна при изменении размеров окна. В поле hbrBackground установлена одна из предоставляемых кистей системы(белый цвет). Все предоставляемые системой стили и кисти смотрите в справочнике.

Функция TranslateMessage позволяет обрабатывать сообщения с клавиатуры. В нашем примере это на самом деле не требовалось, но я решил включить эту функцию. В большинстве случаев цикл сообщений имеет именно такой вид. Это может стать шаблоном для ваших GUI программ.

Как видите, код хоть и вырос по сравнению с кодом диалогового окна #32770 более чем в 4 раза, но мне кажется не должен вызывать трудностей.

Всего доброго!

содержание | назад | вперед