Форум программистов, компьютерный форум, киберфорум
Наши страницы
krapotkin
Войти
Регистрация
Восстановить пароль
Блог. Двадцать пять лет Делфи-практики

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

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

Начав с Делфи-2 двадцать пять лет назад, я прошел все версии, испробовал массу технологий, включая работу с БД, с графикой DirectX, связью с серверами и интернетом, разработку на Андроид и IOS, и многое, многое другое.
____________________________________________________________________________________
P.S. все, о чем здесь написано, всего лишь измышления из головы.
совпадения с реальными людьми и фактами случайны.
Рейтинг: 5.00. Голосов: 1.

Процесс инициализации программы, с настройками и подключением к БД

Запись от krapotkin размещена 20.08.2017 в 20:01
Обновил(-а) krapotkin 12.05.2018 в 06:36

Пока не началось
Все шаги по разбору на старте приложения я стараюсь выполнять в переопределенном конструкторе главной формы.
Это не догма, просто так удобнее.
Мы можем делать это и в событии OnCreate, но тогда если мы решили выйти из приложения, то сначала все равно создастся и криво покажется форма и после этого сразу мигнет и пойдет на выход.
Чтобы исключить эти спецэффекты пишем в классе формы переопределение конструктора
Delphi
1
2
3
4
TMainForm=class(TForm)
...
  constructor Create(AOwner:TComponent); override;
end;
и в конструкторе всё, что нужно на старте.
Вызов исключения в конструкторе приводит к НЕсозданию объекта (а еще вызову деструктора!), поэтому в случае выхода из программы никаких миганий - сразу до свидания...

К главному
Обычно я использую следующие шаги на старте приложения
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
constructor TMainForm.Create(AOwner: TComponent);
begin
  // см. примечание 
  ReadSettings(Settings);
  // в загруженные настройки иногда можно внести изменения, запуская программу с ключами командной строки
  // поэтому выполним еще один метод
  ParseParams(Settings);
  // иногда, как в 1С, нужно при старте выбрать БД для подключения, или еше что-нибудь
  // возможно, это просто форма для логина
  // там же клиент может решить вообще отказаться от входа в программу
  ShowSettingsAndLoginForm(Settings);
  // если клиент отказался, то выходим
  if Application.Terminated then
    Abort; // Abort в конструкторе главной формы приведет к мягкому и тихому выходу из приложения
  // если Settings были изменены в форме, то можно их сохранить. Вот пример
  if Settings.RecentConnections.IndexOf(Settings.Database.ConnectionString)=-1 then
  begin
    Settings.RecentConnections.Add(Settings.Database.ConnectionString);
    Settings.SaveToFile(GetSettingsFilename());end;
  end;
  // создать модуль данных и подключиться к БД
  CreateDatamodule();
  // метод Init для всякой остальной работы - прочитать справочники, заполнить структуры данных
  // слазить в интернет, короче все, что нужно для запуска программы
  // лучше всего запустить для этого отдельный поток а форма тем временем покажется и будет рисовать часики
  // в общем, все, что угодно, что требуется для старта программы
  Init();
end;
Примечание. Про хранение настроек программы я писал в другой заметке

Обращу ваше внимание, что у меня есть глобальная переменная Settings, но в каждый метод я передаю её как параметр.
Это связано с тем, что мы когда-нибудь можем решить, что нам нужны более одного комплекта настроек. Для разных пользователей, для проверки подключения к БД, да и просто для исключения любых зависимостей от глобальных переменных.
Инкапсуляция - замечательная вещь. Все работают только с тем, что им дают непосредственно для работы.

Давайте посмотрим, что может находиться внутри каждого из методов.
ReadSettings. Тут все просто.
Delphi
1
 Settings:=TAS_Settings.CreateFromFile(GetSettingsFilename());
ParseParams
Кликните здесь для просмотра всего текста
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
procedure TfMain.ParseParams;
var
  i:integer;
begin
  Settings.Database.ParseParams;
 
  i := 1;
  while i <= ParamCount do
  begin
    if AnsiSameText(paramstr(i), '-ClearReports') then
      Settings.ClearReports := true
    else if AnsiSameText(paramstr(i), '-lang') and (i<paramcount) then
    begin
      Settings.reportuiresource := paramstr(i+1);
      inc(i);
    end;
    inc(i);
  end;
end;

тут стоит обратить внимание, что настройки БД у меня сами умеют лазить по строке параметров и заполнять себя данными оттуда

ShowSettingsAndLoginForm
Здесь стоит конструкция, описанная в заметке Как правильно сделать форму логина
может, с небольшими вариациями
Кликните здесь для просмотра всего текста
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  fSettings:=tfsettings.Create(Self);
  try
    // форма настроек заполняется из хранилища этих самых настроек
    // которое передано в этот метод через параметр Settings
    fSettings.LoadFrom(Settings); 
    repeat
      if fsettings.showModal()=mrOk then
      begin
        // форма сохраняет то, что навводил пользователь, в хранилище нестроек
        fsettings.saveTo(Settings);
        try
          // пробуем подключиться к БД с теми настройками, что получились, включая логин/пароль 
          fSettings.fDBSettingsFrame.TryConnect(Settings.Database);
          Break;
        except
          on e:Exception do
            ShowMessage(e.Message);
        end;
      end
      else
        Application.Terminate;
    until Application.Terminated;
  finally
    fSettings.free;
  end;


CreateDatamodule
Именно здесь, а не в AutoCreate создается мой главный модуль данных. Ведь настройки для подключения мы читали и изменяли тоже здесь.
Delphi
1
2
  dm:=TDM.Create(Application);
  dm.tryConnect(Settings.database);
попытка коннекта выглядит примерно так:
Delphi
1
2
3
4
5
6
7
8
9
10
procedure TDM.TryConnect(DBSettings: TDBSettings);
begin
  Db.DBParams.Values['sql_role_name'] := DBSettings.Role;
  Db.DBParams.Values['user_name'] := DBSettings.user;
  Db.DBParams.Values['password'] := DBSettings.pass;
  Db.DatabaseName := DBSettings.ConnectionString;
  if DBSettings.lib <> '' then
    Db.LibraryName := DBSettings.lib;
  Db.Open();
end;
кстати, коннект вообще говоря я проверял еще в ShowSettingsAndLoginForm
но есть вероятность, что за эти несколько миллисекунд что-то пошло не так и подключение не состоится.
Что ж. В этом случае мы получим Exception в конструкторе и, следовательно, выйдем из программы.
Размещено в Без категории
Просмотров 521 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru