|
|
|||||||||||||||||||||||||||||
|
Об одном методе создания мастеровИсточник: delphiplus Василий Кругаль
Недавно мне необходимо было быстро создать двух мастеров для двух отдельных, но близких по функционалу приложений. В процессе анализа требований выяснилось, что часть страниц одного мастера может быть использована как в качестве страниц второго мастера, так и самостоятельно вне мастера в разные моменты выполнения приложений. После поиска в Интернете я не нашел подходящего компонента, который позволял бы повторно использовать отдельные страницы мастера. Поэтому пришлось изобретать что-то свое. О том, что у меня получилось и изложено в этой заметке. Прежде всего, необходимо было решить основную задачу мастера - это реализовать механизм определения списка страниц, механизм навигации по этому набору и метод сбора и форму хранения данных, введенных пользователем в процессе выполнения мастера. В качестве реализации страницы я использовал класс TFrame (кадр), т.к. TFrame может быть использован повторно. Таким образом, набор страниц мастера превращается в набор кадров, и тогда навигация превращается в воспроизведение этого набора кадров. Каждый кадр в наборе должен обеспечить три основные функции:
Первая функция реализуется в каждом конкретном случае индивидуально, т.к. довольно сложно придумать некую простую единую реализацию для всех видов кадров. Вторая функция вполне может быть реализована в виде единого интерфейса, который должен реализовать каждый кадр. В качестве интерфейса я использовал следующий интерфейс: unit wizardFrameIntf; interface uses Classes, XMLIntf; type IWizardFrameIntf = interface // Подключение кадра. Вызывается мастером при открытии. // Метод может быть использован кадром для восстановления // настроек, установления значений // по умолчанию и т.п. procedure connect(); // Отключение кадра. Вызывается мастером при закрытии. // Метод может быть использован кадром для сохранения настроек. procedure disconnect(); // Определение наименования кадра. Вызывается мастером при открытии // кадра для определения заголовка окна мастера для открываемого кадра. function getCaption():String; // Обработка события Idle приложения. Вызывается всякий раз, когда // приложение переходит в состояние idle. Метод может быть использован // для определения текущего состояния кадра. procedure idle(); // Обработка события установки фокуса в кадре. Вызывается мастером при // открытии кадра. Метод может быть использован для установления // начального фокуса ввода в кадре. procedure setFrameFocus(); // Проверка возможности перехода к следующему кадру. Вызывается мастером // при попытке пользователя перейти на следующий кадр. Метод может быть // использован для проверки правильности ввода данных. function canGoNext():Boolean; // Сбор (сериализация) данных кадра. Вызывается мастером при завершении // ввода данных и формировании XML документа, содержащего результат // работы мастера. Метод должен быть использован для записи результата // ввода данных кадра в виде дочерних элементов элемента inode. procedure serialize(inode:IXMLNode); end; Последняя процедура (serialize) реализует третью функцию - механизм сбора и сохранения данных, введенных пользователем. В качестве формата хранения данных я использовал XML документ как наиболее подходящий с моей точки зрения. Таким образом, каждый кадр оформляется в виде наследника класса TFrame, реализующего интерфейс IwizardFrameIntf. Вот пример реализации кадра для ввода личных данных (фамилия, имя, отчество и адрес электронной почты): unit nameWizardFrameUnit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, XMLIntf, Dialogs, ComCtrls, ExtCtrls, StdCtrls, wizardFrameIntf; const _NODE_NAME_ = 'name'; // имя тэга в итоговом XML документе // для хранения личных данных _CAPTION_ = 'Личные данные'; // заголовок кадра _NOT_ALL_DATA_TYPED_IN_ = 'Поля "Фамилия" и/или "Имя" должны быть заданы'; type TNameWizardFrame = class(TFrame,IWizardFrameIntf) pan: TPanel; lFirst: TLabel; lLast: TLabel; lMiddle: TLabel; lEmail: TLabel; email: TEdit; middle: TEdit; last: TEdit; first: TEdit; private // методы интерфейса IWizardFrameIntf procedure idle(); function getCaption():String; procedure connect(); procedure disconnect(); procedure serialize(inode:IXMLNode); procedure setFrameFocus(); function canGoNext():Boolean; public end; implementation {$R *.dfm} // подключение кадра procedure TNameWizardFrame.connect(); begin // здесь можно вставить код для установки значений по умолчанию, // восстановления значений, введенных пользователем при предыдущем // вызове мастера и т.п. end; // отключение кадра procedure TNameWizardFrame.disconnect(); begin // здесь можно вставить код для сохранения // значений, введенных пользователем end; // определение наименования кадра function TNameWizardFrame.getCaption():String; begin result:= _CAPTION_; end; // обработка события Idle приложения procedure TNameWizardFrame.idle(); begin // здесь можно вставить код для определения // состояния элементов кадра и его отображения end; // обработка события установки фокуса в кадре procedure TNameWizardFrame.setFrameFocus(); begin first.SetFocus(); end; // проверка возможности перехода к следующему кадру function TNameWizardFrame.canGoNext():Boolean; begin result:= true; // пользователь должен ввести фамилию и имя => проверим, так ли это if ((first.text = '') or (last.text = '')) then begin showMessage(_NOT_ALL_DATA_TYPED_IN_); if (first.text = '') then first.SetFocus() else if (last.text = '') then last.SetFocus(); result:= false; end; end; // сериализация данных кадра procedure TNameWizardFrame.serialize(inode:IXMLNode); var node:IXMLNode; begin // сохраним значения, введенные пользователем в виде XML фрагмента if (inode <> nil) then begin node:= inode.AddChild(_NODE_NAME_,''); with node.AddChild(first.name,'') do NodeValue:= first.Text; with node.AddChild(last.name,'') do NodeValue:= last.Text; with node.AddChild(middle.name,'') do NodeValue:= middle.Text; with node.AddChild(email.name,'') do NodeValue:= email.Text; end; end; end. Теперь осталось реализовать механизм проигрывания (навигации) кадров, который я выполнил в виде отдельной формы: unit wizardPlayerFormUnit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, wizardFrameIntf, AppEvnts, Contnrs, XMLIntf, XMLDoc; Const // текст подтверждения закрытия мастера _CONFIRM_CLOSE_ = 'Вы действительно хотите завершить?'; // текст подтверждения создания объекта мастера _WIZARD_FINISHED_ = 'Сбор данных завершен. Создать '; // _NEXT_ = 'Вперед'; _READY_ = 'Готово'; // заготовка XML документа с данными пользователя _RESULT_XML_ = '<?xml version="1.0" encoding="windows-1251"?> Данная форма может служить для проигрывания любого набора кадров. Далее пример фрагмента кода для запуска мастера: with TWizardPlayerForm.Create(nil) do begin // определим наименование объекта - // результата работы мастера (здесь - Контакт) objectTitle:= 'Контакт'; try // Добавим кадр "личные данные" addFrame(TNameWizardFrame); // Добавим кадр "адрес" addFrame(THomeWizardFrame); // Добавим кадр "Данные о работе" addFrame(TWorkWizardFrame); . . . // Создадим новый контакт с помощью нашего мастера if (showModal() = mrOk) then begin // отобразим результат выполнения мастера showMessage(resultXml); end; finally free(); end; end; Ссылки по теме
Файлы для загрузки
|
|