Справочное руководство по Delphi

       

Понимание событий


Событийное программирование есть не только в Windows, и данную черту можно реализовать не только в операционной системе. Например, любая DOS программа может быть основана на простом цикле, работающем все время жизни программы в памяти. Ниже вы найдете гипотетический пример, как данный код может выглядеть:

begin

InitializeMemory;

repeat

CheckForMouseEvent(Events);

CheckForKeyPress(Events)

HandleEvents(Events);

until Done := True;

DisposeMemory;

end.

Это типичный пример программы, ориентированной на события. Она начинается и заканчивается инициализацией и освобождением памяти. В программе присутствует простой цикл repeat..until, который проверяет появление событий от мыши и клавиатуры и затем дает возможность программисту ответить на эти события.

Переменная Events может быть записью с простой структурой:

TEvent = record



X, Y: Integer;

MouseButton: TButton;

Key: Word;

end;

Тип TButton, указанный выше, можно декларировать так:

TButton = (lButton, rButton);

Эти структуры позволяют вам проследить, где находится мышь, каково состояние ее кнопок, и значение нажатой клавиши на клавиатуре. Конечно, это пример очень простой структуры, но заложенные здесь принципы отражают то, что происходит внутри Windows или внутри других систем, ориентированных на события, вроде Turbo Vision. Если бы программа, приведенная выше, была редактором текста, то обработчик HandleEvent для такой программы мог бы иметь вид:

procedure HandleEvent(Events: TEvent);

begin

case Events.Key of

’A’..’z’: Write(Events.Key);

EnterKey: Write(CarriageReturn);

EscapeKey: Done := True;

end;

end;

Согласно коду выше, программа будет печатать букву ‘a’ при нажатии этой клавиши и перейдет на новую строку, если нажата клавиша ‘Enter’. Нажатие ‘Esc’ приведет к завершению программы.

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


Надеюсь, что приведенный пример дает некоторое понимание работы ориентированной на события системы. Единственное, что осталось пропущенным - почему система Windows так спроектирована.

Одной из основных причин, почему Microsoft сделал Windows по такой схеме, является тот факт, что множество задач работает в среде одновременно. В многозадачных системах операционная система должна знать, щелкнул ли пользователь мышкой на определенное окно. Если это окно было частично перекрыто другим, то это становится известно операционной системе и она перемещает окно на передний план. Понятно, что неудобно заставлять само окно выполнять эти действия. Операционной системе лучше обрабатывать все нажатия клавиш и кнопок на мыши и затем передавать их в остальные программы в виде событий.

Если кратко, программист в Windows почти никогда не должен напрямую проверять “железо”. Система выполняет эту задачу и передает информацию программе в виде сообщений.

Когда пользователь щелкает мышкой, операционная система обрабатывает это событие и передает его в окно, которое должно обработать данное событие. Созданное сообщение, в этом случае, пересылается в некую процедуру DefWindowProc окна (default window procedure). DefWindowProc - аналог процедуры HandleEvent из примера, приведенного выше.

Каждое окно в Windows имеет свою DefWindowProc. Чтобы полностью понять данное утверждение, представьте, что каждая кнопка, каждый ListBox, каждое поле ввода и т.д. на самом деле являются окнами и имеют свою процедуру DefWindowProc. Это очень гибкая и мощная система, но она может заставить программиста писать очень сложный код. Delphi дает возможность быть защищенным от такой структуры программы.

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

Если посмотреть на DefWindowProc в справочнике по Windows API, то можно увидеть следующее определение:



function DefWindowProc(Wnd: HWnd; Msg, wParam: Word;

lParam: LongInt);

Каждое сообщение, посылаемое в окно, состоит из четырех частей: первая часть - handle окна, получающего сообщение, Msg сообщает, что произошло а третья и четвертая части (wParam и lParam) содержат дополнительную информацию о событии. Вместе эти четыре части являются аналогом показанной выше структуры TEvent.

Вторая часть сообщения имеет длину 16 бит и сообщает, что за событие произошло. Например, если нажата левая кнопка на мыши, то переменная Msg содержит значение WM_LBUTTONDOWN. Существуют десятки различного типа cообщений и они называются вроде WM_GETTEXT, WM_HSCROLL, WM_GETTEXTLENGTH и т.п. Список всех сообщений можно видеть в справочнике по Windows API (on-line help).

Последние две переменные, длиной 16 и 32 бита, называются wParam и lParam. Они сообщают программисту важную дополнительную информацию о каждом событии. Например при нажатии кнопки мыши, lParam содержит координаты указателя мыши.

Одна из хитростей заключается в том, как выделить нужную информацию из этих переменных. В большинстве случаев Delphi освобождает вас от необходимости выполнять данную задачу. Например, в обработчике события OnMouseDown для формы вы просто используете координаты X и Y. Как программисту, вам не нужно прилагать усилия для получения сообщения и связанных с ним параметров. Все, что связано с событиями, представлено в простом и непосредственном виде:

procedure TForm1.FormMouseDown(Sender: TObject;

Button: TMouseButton;

Shift: TShiftState;

X, Y: Integer);

Итак, если подвести итог, то должно стать ясным следующее:



  • Windows является системой ориентированной на события;


  • События в Windows принимают форму сообщений;


  • В недрах VCL Delphi сообщения Windows обрабатываются и преобразуются в более простую для программиста форму;


  • Обработка событий в Delphi сводится к написанию для каждого объекта своих обработчиков;


  • События в программе на Delphi вызываются не только сообщениями Windows, но и внутренними процессами.









        1. Содержание раздела