Библиотека программиста

«Очень важно не прерывать вопросов. Любопытство имеет свое право на существование»

Альберт Эйнштейн

Главная страница > Язык Object Pascal > 27. Введение в обработку сообщений

27. Введение в обработку сообщений

Сообщения, вместе с событиями, играют ключевую роль в программировании для Windows. Когда приложение создает окно, оно регистрирует оконную процедуру в ядре Windows (Windows kernel). Оконная процедура (функция в терминах языка С) – это подпрограмма, которая обрабатывает сообщения, поступающие окну как некоторой функциональной части приложения. Здесь под "окном" понимается не только собственно окно как изображение на экране, но и все другие объекты, производные от класса TWinControl.

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

Delphi существенно упрощает обработку сообщений. Каждый компонент наследует полную систему обработки сообщений, включающую обработчик сообщений по умолчанию (message handler). Программист должен писать обработчик только для собственных сообщений. При этом, как правило, в конце обработки сообщения вызывается обработчик по умолчанию.

Главным преимуществом системы обработки сообщений в Delphi является то, что можно послать любое сообщение любому компоненту (окну) в любое время. Например, следующий код обеспечивает завершение приложения:

Procedure TForm1.Button1Click(Sender: TObject);

var Msg : TWMCommand;

Begin

Msg.Msg:=WM_Close;

Dispatch(Msg);

End;

Если компонент не имеет обработчика поступившего сообщения, эту работу выполняет обработчик по умолчанию, который обыкновенно просто игнорирует сообщение. Обработка сообщений в Delphi является встроенной на уровне класса TObject, в котором для этой цели определены два метода:

procedure DefaultHandler(var Message); virtual;

procedure Dispatch(var Message);

В целом система обработки сообщений выглядит следующим образом. Delphi регистрирует метод с именем MainWndProc как оконную процедуру для каждого окна приложения. Эта процедура содержит блок обработки исключительных ситуаций (exception-handling block) и передает поступившее сообщение виртуальному методу с именем WndProc. Вызов WndProc заключен в цикл обработки исключительных ситуаций для того, чтобы приложение могло обработать возникшую исключительную ситуацию. При возникновении исключения вызывается метод класса HandleException. Метод WndProc описан уже в классе TControl (TObject -> TPersistent -> TComponent -> TControl) и перекрыт в классе TWinControl. Метод MainWndProc описан в классе TWinControl.

Сам по себе метод MainWndProc не является виртуальным и не содержит никакой специальной обработки сообщений, он только обеспечивает передачу сообщения WndProc. Вся специфика заключена в виртуальном методе WndProc, который каждым компонентом перекрывается и реализуется по-своему.

Метод(ы) WndProc проверяет поступающие сообщения, отсекая те из них, которые недопустимы в данный момент времени. Например, если какой-либо объект перемещается (dragging), этот метод не пропускает сообщения от клавиатуры. В конечном счете WndProc вызывает статический метод Dispatch, который отыскивает метод, ответственный за обработку данного сообщения.

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

Краснов – пример WinMin к главе 7 (Chapter 1\Ex07).

GENERIC.C contains code for the Generic application. It includes GENERIC.H.

/********************************************************************\

* generic.c: Source code for generic *

* *

* Comments: Generic Application *

* *

* Functions: *

* WinMain - Application entry point *

* MainWndProc - main window procedure *

* AboutDlgProc - dialog procedure for About dialog *

* *

\********************************************************************/

/********************* Header Files *********************/

#include <windows.h>

#include "generic.h"

/********************* Prototypes ***********************/

LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM, LPARAM );

LRESULT WINAPI AboutDlgProc( HWND, UINT, WPARAM, LPARAM );

/******************* Global Variables ********************/

HANDLE ghInstance;

/********************************************************************\

* Function: int PASCAL WinMain(HINSTANCE, HINSTANCE, LPSTR, int) *

* *

* Purpose: Initializes Application *

* *

* Comments: Register window class, create and display the main *

* window, and enter message loop. *

* *

* *

\********************************************************************/

int PASCAL WinMain( HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpszCmdLine,

int nCmdShow )

{

WNDCLASS wc;

MSG msg;

HWND hWnd;

if( !hPrevInstance )

{

wc.lpszClassName = "GenericAppClass";

wc.lpfnWndProc = MainWndProc;

wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );

wc.hCursor = LoadCursor( NULL, IDC_ARROW );

wc.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );

wc.lpszMenuName = "GenericAppMenu";

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

RegisterClass( &wc );

}

ghInstance = hInstance;

hWnd = CreateWindow( "GenericAppClass",

"Generic Application",

WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL,

0,

0,

CW_USEDEFAULT,

CW_USEDEFAULT,

NULL,

NULL,

hInstance,

NULL

);

ShowWindow( hWnd, nCmdShow );

while( GetMessage( &msg, NULL, 0, 0 ) ) {

TranslateMessage( &msg );

DispatchMessage( &msg );

}

return (int)msg.wParam;

}

/********************************************************************\

* Function: LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM) *

* *

* Purpose: Processes Application Messages *

* *

* Comments: The following messages are processed *

* *

* WM_PAINT *

* WM_COMMAND *

* WM_DESTROY *

* *

* *

\********************************************************************/

LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam,

LPARAM lParam )

{

PAINTSTRUCT ps;

HDC hDC;

switch( msg ) {

/**************************************************************\

* WM_PAINT: *

\**************************************************************/

case WM_PAINT:

hDC = BeginPaint( hWnd, &ps );

TextOut( hDC, 10, 10, "Hello, World!", 13 );

EndPaint( hWnd, &ps );

break;

/**************************************************************\

* WM_COMMAND: *

\**************************************************************/

case WM_COMMAND:

switch( wParam ) {

case IDM_ABOUT:

DialogBox( ghInstance, "AboutDlg", hWnd, (DLGPROC)

AboutDlgProc );

break;

}

break;

/**************************************************************\

* WM_DESTROY: PostQuitMessage() is called *

\**************************************************************/

case WM_DESTROY:

PostQuitMessage( 0 );

break;

/**************************************************************\

* Let the default window proc handle all other messages *

\**************************************************************/

default:

return( DefWindowProc( hWnd, msg, wParam, lParam ));

}

return 0;

}

/********************************************************************\

* Function: LRESULT CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM)*

* *

* Purpose: Processes "About" Dialog Box Messages *

* *

* Comments: The About dialog box is displayed when the user clicks *

* About from the Help menu. *

* *

\********************************************************************/

LRESULT CALLBACK AboutDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )

{

switch( uMsg ) {

case WM_INITDIALOG:

return TRUE;

case WM_COMMAND:

switch( wParam ) {

case IDOK:

EndDialog( hDlg, TRUE );

return TRUE;

}

break;

}

return FALSE;

}





<< Предыдущая статья
«26. Конструкторы и деструкторы»
Следующая статья >>
28. Обработчики сообщений