Механизм обработки сообщений в Delphi
В число базовых в иерархии классов Delphi входят класс TComponent и построенный на его базе класс TControl, который содержит обработчики многих событий, а также методы для преобразования стандартных Windows-сообщений в собьггия в контексте Delphi. Отметим, что эта преобразования во многом напоминают преобразования (message crackers), выполняемые в файле WINDOWSX.H, входящем в состав SDK Windows 3.1. Класс TControl выступает предком для многих визуальных компонентов, входящих в состав Delphi. В частности, класс TControl содержит обработчики сообщений, относящихся к манипулятору «мышь»: WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN, WM_LBUTTONDBLCLK, WM_RBUT-TONDBLCLK, WM_MBUTTONDBLCLK, WM_MOUSEMOVE, WMJLBUTTONUP, WM_RBUTTONUP и WM_MBUTTONUP.
Чтобы представить себе механизм обработки сообщений в Delphi, давайте, например, посмотрим на обработчик сообщения WMMOUSEMOVE. Обработчик этого сообщения вызывает метод MouseMove и передает ему три параметра — координаты курсора мыши при юзникновении данного события и информацию о состоянии клавиш Shift, Alt и Ctrl, преобразованную с помощью функции KeysToShiftState. Эта функция заполняет тип TShiftState информацией, взятой из параметра wParam оригинального сообщения Windows:
Значение | Описание | Параметр Shift |
MK_SHIFT | Нажата клавиша Shift | ssShift |
MK_CONTROL | Нажата клавиша Ctrl | ssCtr! |
MK_LBUTTON | Нажата левая кнопка мыши | ssLeft |
MK_RBUTTON | Нажата правая кнопка мыш | ssRight |
MK_MBUTTON | Нажата средняя кнопка мьи | ssMiddle |
Получив преобразованное сообщение, метод MouseMove преобразует его в событие OnMouseMove и передает его обработчику этого события:
if Assigned(FOnMouseMove) {Обработчик существует?}
then FOnMouseMove(Self, Shift, X, Y);
Обработка сообщения WMLBUTTONDOWN выглядит чуть сложнее. Обработчик этого сообщения проверяет, может ли компонент обрабатывать сообщения от мыши, а затем вызывает метод DoMouseDown, передавая ему неизмененное сообщение и параметр, указывающий на то, что нажата левая кнопка мыши. Метод DoMouseDown «распаковывает» оригинальное сообщение Message и передает параметры методу MouseDown:
MouseDown(Button, KeysToShiftState(Keys) + Shift, XPos, YPos);
Получив преобразованное таким образом сообщение, метод MouseDown преобразует его в событие OnMouseDown и передает его обработчику этого события:
if Assigned(FOnMouseDown)
{Обработчик существует?}
then FOnMouseDown(Self, Button, Shift, X, Y);
Точно так же сообщения о нажатии правой и средней кнопок мыши (WM_RBUTTONDOWN и WM MBUTTONDOWN) преобразуются в событие OnMouseDown. Единственным исключением является то, что в случае нажатия правой кнопки мыши дополнительно проверяется наличие у интерфейсного элемента локального (popup) меню:
Control := Self;
while Control <> nil do
begin
if (Control.PopupMenu <> nil)
and Control.PopupMenu.AutoPopup then
begin
Control.Perform(CM_CANCELMODE, 0, 0);
with ClientToScreen(Pos) do
Control.PopupMenu.Popup(X, Y);
Exit;
end;
Control := Control.Parent;
end;
С обработчиками событий от клавиатуры дело обстоит иначе. Во-первых, они рассматриваются как нотификационные сообщения и имеют отличные от стандартных названия:
Нотификационное сообщение | Сообщение ядра Windows |
CN_KEYDOWN | WM_KEYDOWN |
CNKEYUP | WM_KEYUP; |
CN_CHAR | WM_CHAR |
CN_SYSKEYDOWN | WM_SYSKEYDOWN |
CN_SYSCHAR | WM_SYSCHAR |
и включают специальные обработчики, которые умеют распознавать многие клавиши, обладающие функциональностью в среде Delphi, обработкой же других клавиш занимается процедура WndProc (вызываемая методом Perform). Отмечу, что создание специальных обработчиков вызвано скорее всего тем, что разработчик может создать объект — наследник любого компонента и в нем переопределить метод — обработчик того или иного сообщения Windows, тем самым нарушив функциональность ядра Delphi (если не вызван унаследованный обработчик через ключевое слово inherited). Чтобы избежать этого, все ключевые (для функциональности Delphi-приложения) сообщения Windows имеют специальные индексы. Несмотря на то что эта процедура имеет название WndProc(то есть «оконная процедура»), все, чем она занимается, — это обработка сообщений, связанных с перемещением элементов. Далее в игру вступает еще одна процедура — Dispatch.Именно эта процедура (а точнее, метод объекта TObject) является «сердцем» механизма обработки сообщений. Она и вызывает конкретные обработчики Windows-сообщений, указанные как индекс (соответствующий номеру сообщения и задаваемый при описании метода-обработчика) в таблице виртуальных методов объекта.
Что вы узнали в этой главе
· О всех событиях, происходящих в системе, ядро Windows информирует окна путем посылки сообщений их оконным функциям.
· Delphi дает разработчику полный доступ к событийной модели работы Windows, при этом максимально упрощая процесс обработки того или иного события.
· Изначально источником событий от клавиатуры или мыши является драйвер клавиатуры или мыши, затем ядро Windows преобразует их в стандартный вид и пересылает окну программы.
· Протокол Drag and Drop позволяет пользователям легко манипулировать компонентами внутри формы.
· Событие OnChange,рассматриваемое в этом разделе, имеет чрезвычайно важное значение в цикле работы приложения. Оно возникает в том случае, когда содержимое компонента изменено.
· Создавая собственные обработчики событий, необходимо помнить следующее:
- обработчики всегда являются процедурами;
- обработчики объявляются с помощью директивы message;
- после директивы message всегда следует константа, указывающая номер обрабатываемого сообщения;
- обработчики имеют всего один параметр типа TMessage.
Страница Additional
На странице Additional размещены объекты, позволяющие создать более красивый пользовательский интерфейс программы.
![]() |
Список компонент:
![]() |
TBitBtn -кнопка вроде TButton, однако на ней можно разместить картинку (glyph). TBitBtn имеет несколько предопределенных типов (bkClose, bkOK и др), при выборе которых кнопка принимает соответствующий вид. Кроме того, нажатие кнопки на модальном окне (Form2.ShowModal) приводит к закрытию окна с соответствующим модальным результатом (Form2.ModalResult).
![]() |
TSpeedButton -кнопка для создания панели быстрого доступа к командам (SpeedBar). Пример - SpeedBar слева от Палитры Компонент в среде Delphi. Обычно на данную кнопку помещается только картинка (glyph).
![]() |
TTabSet - горизонтальные закладки. Обычно используется вместе с TNoteBook для создания многостраничных окон. Название страниц можно задать в свойстве Tabs. Но проще это сделать в программе при создании формы (OnCreate) :
TabSet1.Tabs := Notebook1.Pages;
А для того, чтобы при выборе закладки страницы перелистывались нужно в обработчике события OnClick для TTabSet написать:
Notebook1.PageIndex := TabSet1.TabIndex;
![]() |
TNoteBook - используется для создания многостраничного диалога, на каждой странице располагается свой набор объектов. Используется совместно с TTabSet.
![]() |
TTabbedNotebook - многостраничный диалог со встроенными закладками, в данном случае - закладки сверху.
![]() |
TMaskEdit -аналог TEdit, но с возможностью форматированного ввода. Формат определяется в свойстве EditMask. В редакторе свойств для EditMask есть заготовки некоторых форматов: даты, валюты и т.п. Спец. символы для маски можно посмотреть в Справочнике.
![]() |
TOutline - используется для представления иерархических отношений связанных данных. Например - дерево директорий.
![]() |
TStringGrid -служит для представления текстовых данных в виде таблицы. Доступ к каждому элементу таблицы происходит через свойство Cell.
![]() |
TDrawGrid - служит для представления данных любого типа в виде таблицы. Доступ к каждому элементу таблицы происходит через свойство CellRect.
![]() |
TImage -отображает графическое изображение на форме. Воспринимает форматы BMP, ICO, WMF. Если картинку подключить во время дизайна программы, то она прикомпилируется к EXE файлу.
![]() |
TShape -служит для отображения простейших графических объектов на форме: окружность, квадрат и т.п.
![]() |
TBevel - элемент для рельефного оформления интерфейса.
![]() |
THeader- элемент оформления для создания заголовков с изменяемыми размерами для таблиц.
![]() |
TScrollBox - позволяет создать на форме прокручиваемую область с размерами большими, нежели экран. На этой области можно разместить свои объекты.
Страница Dialogs
![]() |
На странице Dialogs представлены компоненты для вызова стандартных диалогов Windows. Внешний вид диалогов зависит от используемой версии Windows. Объекты, представленные на данной странице невидимы во время выполнения и вызов диалогов происходит программно, например:
if OpenDialog1.Execute then Image1.Picture.LoadFromFile(OpenDialog1.FileName);
Диалоги Windows в порядке появления на странице Dialogs:
· OpenDialog; выбрать файл
· SaveDialog; сохранить файл
· FontDialog; настроить шрифт
· ColorDialog; выбор цвета
·
· PrintDialog; печать
· PrinterSetupDialog; настройка принтера
· FindDialog; поиск строки
· ReplaceDialog; поиск с заменой
Страница System
![]() |
Страница представляет набор компонент для доступа к некоторым системным сервисам типа таймер, DDE, OLE и т.п.
![]() |
TTimer -таймер, событие OnTimer периодически вызывается через промежуток времени, указанный в свойстве Interval. Период времени может составлять от 1 до 65535 мс.
![]() |
TPaintBox -место для рисования. В обработчики событий, связанных с мышкой передаются относительные координаты мышки в TPaintBox, а не абсолютные в форме.
![]() |
TFileListBox -специализированный ListBox, в котором отображаются файлы из указанной директории (св-во Directory). На названия файлов можно наложить маску, для этого служит св-во Mask. Кроме того, в св-ве FileEdit можно указать объект TEdit для редактирования маски.
![]() |
TDirectoryListBox -специализированный ListBox, в котором отображается структура директорий текущего диска. В св-ве FileList можно указать TFileListBox, который будет автоматически отслеживать переход в другую директорию.
![]() |
TDriveComboBox -специализированный ComboBox для выбора текущего диска. Имеет свойство DirList, в котором можно указатьTDirectoryListBox, который будет отслеживать переход на другой диск.
![]() |
TFilterComboBox - специализированный ComboBox для выбора маски имени файлов. Список масок определяется в свойстве Filter. В свойстве FileList указывается TFileListBox, на который устанавливается маска.
!!!!С помощью последних четырех компонент (TFileListBox, TDirectoryListBox, TDriveComboBox, TFilterComboBox) можно построить свой собственный диалог выбора файла, причем для этого не потребуется написать ни одной строчки кода.
![]() |
TMediaPlayer -служит для управления мултимедйными устройствами (типа CD-ROM, MIDI и т.п.). Выполнен в виде панели управления с кнопками Play, Stop, Record и др. Для воспроизведения может понадобиться как соответствующее оборудование, так и программное обеспечение. Подключение устройств и установка ПО производится в среде Windows. Например, для воспроизведения видео, записанного в формате AVI, в потребуется установить ПО MicroSoft Video (в Windows 3.0, 3.1, WFW 3.11).
![]() |
![]() |
TOLEContainer - контейнер, содержащий OLE объекты. Поддерживается OLE 2.02.
TDDEClientConv,TDDEClientItem, TDDEServerConv, TDDEServerItem -4 объекта для организации DDE. С помощью этих объектов можно построить приложение как DDE-сервер, так и DDE-клиент.
Страница VBX
![]() |
![]() |
Поскольку формат объектов из MicroSoft Visual Basic (VBX) является своего рода стандартом и существует большое количество библиотек таких объектов, то в Delphi была предусмотрена совместимость с этим форматом. VBX версии 1.0 можно включить в Палитру Компонент Delphi и использовать их как “родные” компоненты (в том числе, выбирать их в качестве предков и наследовать свойства и методы).
TBiSwitch -двухпозиционный переключатель.
![]() |
TBiGauge - прогресс-индикатор.
![]() |
TBiPict -аналог TImage.
![]() |
TChartFX -деловая графика.