Основой любой Windows-программы
является окно, даже если программа за все
время работы ни разу не появляется на
экране. Я сейчас хочу подробно разобрать
процесс создания окна на примере
простейшей windows-программы, кроме главного
окна ничего не имеющей.
Программа winmin
program winmin; uses windows, messages; {!Модули windows и messages самые необходимые — они обязательно должны быть объявлены в начале каждой Вашей программы!} var wc : TWndClassEx;//Переменная шаблона класса окна MainWnd : HWND; //Описатель главного окна Mesg : TMsg; //Переменная для цикла сбора сообщений { Далее следует оконная процедура главного окна. Обратите внимание на служебное слово stdcall оно вынуждает компилятор генерировать особый вид кода, который может быть вызван любой windows-программой, без этого служебного слова программа не сможет работать вообще!} function WindowProc(wnd:HWND; Msg : Integer; Wparam:Wparam; Lparam:Lparam):Lresult; stdcall; Begin {Далее происходит цикл обработки сообщений} case msg of wm_destroy ://Сообщение посылаемое при уничтожении окна Begin postquitmessage(0); exit; Result:=0; End; else Result:=DefWindowProc(wnd,msg,wparam,lparam); end; End; {Переменные xPos,yPos,nWidth,nHeight в принципе не нужны, однако я их завел (и вам рекомендую) для лучшей читабельности программы} var xPos,yPos,nWidth,nHeight : Integer; begin { Далее идет заполнение шаблона класса окна подробное описание полей этой записи см. после текста программы} wc.cbSize:=sizeof(wc); wc.style:=cs_hredraw or cs_vredraw; wc.lpfnWndProc:=@WindowProc; wc.cbClsExtra:=0; wc.cbWndExtra:=0; wc.hInstance:=HInstance; wc.hIcon:=LoadIcon(0,idi_application); wc.hCursor:=LoadCursor(0,idc_arrow); wc.hbrBackground:=COLOR_BTNFACE+1; wc.lpszMenuName:=nil; wc.lpszClassName:='WinMin : Main'; RegisterClassEx(wc);//Регистрация нового класса в системе { Заполнение переменных xPos,yPos,nWidth,nHeight} xPos:=100; yPos:=150; nWidth:=400; nHeight:=250; { Создание главного окна} MainWnd:=CreateWindowEx( 0, //флаги расширенных стилей 'WinMin : Main', //имя класса окна, данное при заполнении структуры wc 'Win Min', //заголовок окна ws_overlappedwindow,//флаги стилей окна {подробнее о стилях см. после текста программы} xPos, //горизонтальная позиция окна yPos, //вертикальная позиция окна nWidth, //ширина окна nHeight, //высота окна 0, //описатель родительского окна (parent) или окна-владельца (owner) 0, //описатель меню окна (меню нет, нет и описателя) Hinstance, //описатель приложения nil //address of window-creation data ); ShowWindow(MainWnd,CmdShow);//Отображаем окно //Цикл обработки сообщений //он может слегка видоизменяться, но эти строчки присутсвуют всегда While GetMessage(Mesg,0,0,0) do begin TranslateMessage(Mesg); DispatchMessage(Mesg); end; end. |
Осталось только уточнить ряд деталей. Во-первых, ВСЁ присутствующее в данной программе (кроме комментариев, разумеется) ОБЯЗАТЕЛЬНО. Укоротить принципиально невозможно, можно, конечно, убрать некоторые переменные, но это сути дела не меняет. Во-вторых, в оконной процедуре могут присутствовать и другие строчки, принимающие сообщения. В-третьих, вызов в оконной процедуре функции DefWindowProc жизненно необходим. DefWindowProc — это оконная процедура по умолчанию, она обеспечивает окну возможность «вести» себя как окну, т.е. перетаскиваться мышкой, сворачиваться, разворачиваться и т.д. Однако не все так плохо, можно писать программы на Win32API не затрачивая таких усилий. Это реализуется при помощи создания приложений, основанных на ресурсах диалоговых окон. Но об этом я подробно напишу позже.
Коротко о записи TWndClassEx. Эта запись представляет собой шаблон, на основе которого будут создаваться окна. Тип TWndClassEx определен в модуле windows следующим образом
TWndClassExA = packed record cbSize : Integer; lpszClassName : PChar; lpszMenuName : PChar; lpfnWndProc : TFNWndProc;//TFNWndProc = Pointer hInstance : HINST; //HINST = Integer hIcon : HICON; hCursor : HCURSOR; cbClsExtra : Integer; cbWndExtra : Integer; style : Integer; hbrBackground : HBRUSH; hIconSm : HICON; end; TWndClassEx = TWndClassExA; |
function FunctionName(wnd:HWND; Msg : Integer; Wparam : Wparam; Lparam : Lparam) : Lresult; stdcall; |
function CreateWindowEx( dwExStyle: Integer; lpClassName: PChar; lpWindowName: PChar; dwStyle: Integer; X, Y : Integer; nWidth, nHeight: Integer; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; |
Ниже приведен список флагов оконных стилей — констант WS_ и описание того, на что влияет добавление этого флага. Напомню, что общий стиль окна получается соединением флагов при помощи операции OR
Это основные флаги стиля, все
остальные можно посмотреть в справке по Delphi
Флаги расширенного стиля окна
Потребность в расширенных стилях возникла из-за того, что стало не хватать флагов обычного стиля (напомню , что их возможно всего 32 штуки). Все флаги расширенного стиля представляют собой константы вида WS_EX_. Список самых важных из них дан ниже
Об остальных стилях см. в справке по Delphi
Для того, чтобы ваша программа
могла принимать сообщения, необходимо
организовать специальный цикл — цикл сбора
сообщений. Обычно он выглядит так:
While GetMessage(Mesg,0,0,0) do begin TranslateMessage(Mesg); DispatchMessage(Mesg); end; |
Однако в отдельных случаях ( когда приложение использует акселераторы либо немодальные диалоговые окна) его вид может изменяться, но об этом будет сказано особо.
Функция GetMessage извлекает сообщения из системной очереди сообщений, либо из очереди сообщений данной программы, она всегда возвращает True, кроме одного случая — сообщения WM_QUIT. Когда функция натыкается на данное сообщение, цикл (а вместе с ним и программа) завершается. Если вы хотите самостоятельно отлавливать сообщение wm_quit, используйте вместо GetMessage PeekMessage.
Функция TranslateMessage выполняет только одну функцию — она отлавливает аппаратные сообщения wm_keydown и wm_sysKeyDown о нажатых клавишах, и если для данной клавиши существует её ascii код, формирует сообщение WM_CHAR и вставляет его в очередь сообщений данного процесса.
Функция DispachMessage отправляет сообщение в оконную функцию.
Назад|Содержание|Вперед |