Диспетчеризация событий — компоненты, связанные с ActionList

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

Действие (action) — реализация некоторого поведения, являющегося реакцией на поступок пользователя, такой, как щелчок на кнопке или на разделе меню — инициаторе действия. Разработан класс TAction и ряд его наследников, реализующих многие стандартные действия, характерные для приложений Windows.

Список действий — компонент типа ActionList, содержащий предусмотренные в приложении действия. Это интерфейс разработчика, упорядочивающий его работу с действиями в процессе проектирования.

Редактор связей — объект типа TActionLink, который поддерживает связь между действиями и инициаторами действий. Редактор связей определяет, какое действие должно выполняться для данного инициатора.

Цель действия — объект, в котором отражается результат действия. Это может быть окно отображения или редактирования текста, набор данных и т.п.

В начале проектирования приложения разработчик должен представить себе список тех действий, которые может осуществлять пользователь. Конечно, в процессе проектирования этот список будет пополняться и изменяться, но некоторое начальное приближение очень полезно продумать заранее. Практическая реализация составленного вами списка действий может начинаться с переноса на проектируемую форму невизуального компонента ActionList, расположенного на странице библиотеки Standard. Сделав на этом компоненте двойной щелчок, вы попадаете в редактор действий (рис. 9.1), позволяющий вводить и упорядочивать действия.

 

Рис. 9.1
Окно редактора действий
 

Щелчок правой кнопкой мыши или щелчок на маленькой кнопочке со стрелкой вниз правее первой быстрой кнопки окна редактирования позволит вам выбрать одну из команд: New Action (новое действие) или New Standard Action... (новое стандартное действие). Первая из них относится к вводу нового действия любого типа. По умолчанию эти действия будут получать имена Action1, Action2 и т.д. Вторая команда открывает окно (рис. 9.2), в котором вы можете выбрать необходимое вам стандартное действие (или сразу несколько действий). После этого в правом окне (Actions) редактора появятся имена выбранных действий, а в левом (Categories) — категории действий.

 

Рис. 9.2
Окно выбора стандартных действий
 

Каждое действие, которое вы внесли в список — это объект типа TAction для нестандартных действий или других производных типов для стандартных. Выбрав в окнах редактора ту или иную категорию или [AllActions] (все категории), а в правом — конкретное действие, вы можете увидеть в Инспекторе Объектов его свойства и события. Вы можете установить свойство Name (имя) — оно появится в правом окне редактора свойств и будет в дальнейшем фигурировать в заголовках обработчиков событий. Можете также установить надпись (Caption), которая далее будет появляться в инициаторах действия — кнопках, разделах меню и т.д. Можете задать быстрые клавиши (Shortcut), надписи на ярлычках подсказок и в строке состояний (Hint), идентификатор темы контекстной справки (HelpContext) и другие обычные для многих компонентов свойства.

Можно для каждого или некоторых действий указать свойство ImageIndex, которое является индексом (начиная с 0) изображения, соответствующего данному действию, в отдельном компоненте списка изображений ImageList (см. раздел 9.3). Этот индекс передастся в дальнейшем компонентам, связанным с данным событием — разделам меню, кнопкам. Если в свойстве Images компонента ActionList указать имя списка, размещенного на форме и заполненного изображениями, то эти изображения появятся также в окне редактора действий (рис. 9.1).

Свойство Category (категория) не имеет отношения к выполнению приложения. Задание категории просто позволяет в процессе проектирования сгруппировать действия по их назначению. Вы можете для каждого действия выбрать категорию из выпадающего списка, или написать имя новой категории и отнести к ней какие-то действия. Например, на рис. 9.1 видна введенная пользователем категория Файлы, к которой отнесены действия, связанные с меню Файл.

На странице событий Инспектора Объектов для каждого действия определено три события: OnExecute, OnUpdate и OnHint.

Событие OnExecute возникает в момент, когда пользователь инициализировал действие, например, щелкнув на компоненте (разделе меню, кнопке), связанном с данным действием. Обработчик этого события должен содержать процедуру, реализующую данное действие. Например, обработчик события OnExecute действия Exit может в простейшем случае иметь вид

procedure TForm1.ExitExecute(Sender: TObject);
begin
 Close;
end;
а в более сложных случаях может содержать проверку возможности закрыть приложение, запросы пользователю и т.д. Одним из преимуществ использования действий является то, что заголовки обработчиков приобретают осмысленный характер и код становится более прозрачным. Действительно, гораздо понятнее заголовок ExitExecute, чем, например, Button7Click или N14Click (попробуйте найти в вашем большом приложении, где эта кнопка Button7 или раздел меню N14). В результате вы избавляетесь от необходимости давать осмысленные имена кнопкам и разделам меню, т.е. облегчаете свою работу с компонентами.

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

Событие OnHint возникает в момент, когда на экране отображается ярлычок подсказки в результате того, что пользователь задержал курсор мыши над компонентом, инициализирующим событие.

Наличие в объекте действия событий OnUpdate и OnHint обогащает ваши возможности по проектированию приложения. Без этого объекта подобные события отсутствуют и их при необходимости приходится моделировать более сложными приемами.

Связь объектов действий с конкретными инициализаторами действий — управляющими элементами типа кнопок, разделов меню и т.д., осуществляется через свойство Action, имеющееся у всех управляющих элементов. Поместите на вашу форму кнопку, и вы увидите в Инспекторе Объектов это свойство. Раскройте его выпадающий список и выберите из него действие, которое вами было предварительно описано. Вы сможете заметить, что после этого в кнопку перенесутся такие свойства объекта действия, как Caption, Hint и др., и что в ее событие OnClick подставится обработчик, предусмотренный вами для данного действия. Если далее вы введете в приложение меню с разделом, соответствующим тому же действию, и укажете в нем то же значение свойства Action, то свойства и обработчики событий объекта действия будут перенесены и на этот раздел меню. Вам не придется повторно задавать значение Hint, Caption и др.

Подобная связь между свойствами объекта действия и свойствами управляющих элементов выполняется классом TActionLink и его наследниками. Передаются в компоненты такие свойства действия, как Caption, Checked, Enabled, HelpContext, Hint, ImageIndex, Shortcut, Visible. Впрочем, в любом компоненте разработчик может изменить переданное в него свойство. Обратной связи TActionLink с компонентами нет, так что эти изменения будут локальными и не отразятся на других компонентах. Если же требуется изменить свойства всех связанных с одним действием компонентов, надо изменять свойство объекта действия. Это облегчает программное управление компонентами, связанными с одним и тем же действием. Например, если в какой-то момент вам надо сделать недоступными (или, наоборот, доступными) два компонента — кнопку Button3 и раздел меню N5, связанные с одним событием (назовем его объект Do), то при отсутствии централизованной диспетчеризации событий через ActionList вам пришлось бы писать два оператора:

Button3.Enabled := false;
N5.Enabled := false;
а при наличии объекта Do — всего один:
Do.Enabled := false;

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

Hosted by uCoz



Проект Delphi Space © Выпуск 2009- 2010