вторник, 29 октября 2013 г.

Полезняшки. С чего мы начинаем приложение в Delphi

Суть заметки в двух словах: организация dpr-файла и вынос мозга инициализации приложения в DataModule.

Эту заметку не стоит рассматривать как единственно верный вариант. Просто я хочу поделиться опытом. Я расскажу, как делаю я и как это делается у нас. Ничего особенного. Но самостоятельно к этому приходят не все и не сразу. А делаю я так, потому что описанный ниже подход облегчает сопровождение проектов (особенно, когда их несколько, и все они потихоньку разрастаются).

Итак, первое, что я всегда делаю после установки Delphi – снимаю флаг с пункта меню Auto create forms & data modules. Этот флаг по умолчанию установлен, наверное, как дань традиции. Однако сразу создавать все формы в приложении не есть хорошо. Я считаю, что ресурсы у системы надо выделять по мере необходимости (ну за исключением совсем простых, либо совсем особых случаев).

Затем устанавливаем пакет BaseForms (для VCL). Или не устанавливаем, но я на BaseForms ещё буду ссылаться.

Далее создаём новый проект. И сразу же удаляем только что созданную форму, т.к. она не базовая. Затем создаём датамодуль, форму которого называем DM, а файл – DataModule.pas. Это будет модуль, координирующий инициализацию и завершение приложения. Теперь можно всё сохранить и дать название нашему приложению. К примеру: MyTestProject. (Да, и добавим ещё AppExt в dpr-файл). Теперь dpr-файл выглядит вот так:

program MyTestProject;

uses
  AppExt,
  Forms,
  DataModule in 'DataModule.pas' {DM: TBaseDataModule};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TDM, DM);
  Application.Run;
end.

Тут хочу акцентировать внимание на том, что в dpr-файле создаётся только DataModule (DM). Остальные формы будут добавляться в uses, но секция begin – end. затрагиваться не будет.

И вот всё самое интересное выносим в DataModule.OnCreate. Это могут быть: SplashScreen, логгер критических ошибок, чтение пользовательских предпочтений, словарь данных, текстовые ресурсы. Здесь же спрашиваем логин/пароль у пользователя, если мы работаем с БД (и если без подключения к БД работать нет смысла). У меня всё это выглядит примерно так:

procedure TAppDataModule.DataModuleCreate(Sender: TObject);
begin
  CheckParamStr;

  PrepareGlobalConfig;

  {$ifdef use_mui}
  PrepareLanguages;
  {$endif}

  CreateSplashScreen;
  try
    ShowSplashScreen;

    PrepareHelp;

    ProgressMsg(stInitialization);
    PrepareConnection;

    ProgressMsg(stDictionary);
    PrepareDictionary;

    ProgressMsg(stAuthentication);
    if QueryConnect then
    try
      AfterConnected;
      ProgressMsg(stLoading);
      PrepareDataModules;
      PrepareMainForm;
    except
      Connection.Disconnect;
      raise;
    end;
  finally
    FreeSplashScreen;
  end;
end;

Пару комментариев к коду. Сначала показываем SplashScreen, чтобы пользователю не было “скучно”. Затем загружаем всё необходимое для работы приложения. QueryConnect в наших приложениях – это отображение полей ввода для пароля/логина к БД прям в окне SplashScreen и запуск цикла с Application.ProcessMessages, чтобы пользователь мог их ввести; плюс N-попыток подключения к БД. Если подключиться не удалось – QueryConnect вернёт False и произойдёт нормальное завершение приложения (т.к. Application.MainForm ещё не определён).

PrepareDataModules – создаёт остальные датамодули. У нас их несколько – один хранит в себе ImageList’ы (т.е. все пиктограммы для тулбаров и меню собраны в одном месте, это очень удобно), другой содержит компоненты FastReport’а и механизмы для работы с отчётами, третий – датасеты (ну у нас не датасеты и генерируется оно автоматически, но инициализировать это тоже надо).

PrepareMainForm – создаёт главную форму приложения, ей будет передано управление в Application.Run сразу после выхода из приведённого обработчика.

Ещё Вы можете обратить внимание на то, что датамодуль у нас называется DM, а код выше я (намеренно) представил от имени TAppDataModule (вместо TDM). Это ещё одно упрощение для сопровождения – TAppDataModule содержит набор виртуальных методов (типа AfterConnected и PrepareMainForm) и является общим для группы проектов. А для конкретного проекта (типа MyTestProject) TDM наследуется от TAppDataModule и содержит уникальные для приложения вещи. (К слову сказать, TAppDataModule и остальные датамодули у нас наследуется от базового датамодуля, по аналогии с формами.)

 

И конечно же есть обработчик DataModule.OnDestroy, я его приводить не буду – понятно, что там содержится код для корректного отключения от БД (если ещё не отключились), сохранение настроек (которые ещё не сохранились), освобождение памяти (которая ещё не освободилась).

5 коммент.:

Александр Люлин комментирует...

Мне нравится... Я сам - "примерно так" делаю...

Анонимный комментирует...

Думаю, что может пригодиться:
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1424

Александр Люлин комментирует...

Николай, мне почему-то кажется, что ссылка должна вам понравиться:
http://18delphi.blogspot.ru/2013/10/vcm-mvc.html

Николай Зверев комментирует...

Спасибо за ссылки. Обе статьи читал - выходил поиском, когда лепил свои базовые формы и писал MDI-приложение (где-то в 2007м году).
Какой-то отпечаток в сознании они безусловно оставили...

vsmihaylovsky комментирует...

Я без главной формы вообще обхожусь. Это связано со старыми приложениями, написанным как куча независимых модальных окон, появляющихся на фоне не нужного окна с меню.
Просто весь код пишу в дпр файле. Как то так:
Application.Initialize;
Application.Title := 'Title ';
TSomeFrom.show_form;

Это упрощено - если в приложении одна форма. Иначе запускается синглтон который управляет окнами.

Отправить комментарий

.

.