Как мне избежать вызова Application.CreateForm дважды? - PullRequest
5 голосов
/ 01 февраля 2010

Я наткнулся на эту страницу Почему бы мне не позвонить Application.CreateForm . Теперь у меня есть такой код:

SplashForm := TSplashForm.Create(Application);
SplashForm.Show;
SplashForm.Update; // force update
Application.Initialize;
Application.CreateForm(TClientData, ClientData);
SplashForm.Update; // force update
Application.CreateForm(TClientMainForm, ClientMainForm);
Application.ShowHint := True;

Application.Run;
ClientMainForm.ServerConnected := false;
FreeAndNil(ClientMainForm);
FreeAndNil(ClientData);

Сначала создается форма всплеска, затем модуль данных и, наконец, основная форма. На странице написано, что Application.CreateForm не должен вызываться дважды. Нужно ли менять код выше?

Ответы [ 4 ]

5 голосов
/ 01 февраля 2010

В использовании Application.CreateForm несколько раз нет ничего плохого. Но это вводит глобальные переменные для каждой формы, которые могут быть запахом кода. К сожалению, IDE создает один для каждой формы. Хотя вы можете удалить их, если хотите.

Лучший способ - создать форму, когда она вам нужна, и выпустить ее, когда вы будете готовы. Таким образом, вы используете только Application.CreateForm для основной формы.

Основной модуль данных может быть создан с помощью главной формы. Но это тоже может быть глобальным, просто дело вкуса.

Таким образом, чтобы ответить на вопрос, вы можете избежать Application.CreateForm, создавая и выпуская формы локально.

В статье упоминается побочный эффект Application.CreateForm (первая заполненная форма является основной формой). Поэтому могут возникать неожиданные побочные эффекты, если основная форма создает другие формы с использованием Application.CreateForm.

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

1 голос
/ 01 февраля 2010

Когда я писал эту статью, я думал в первую очередь о коде вне файла DPR. Люди видят код создания формы, сгенерированный IDE, в файле DPR и считают, что это лучший способ создания форм, поэтому они используют его в других местах своих программ. Иногда они используют его в обработчике событий OnCreate основной формы для создания других форм, в которых нуждается их программа, а затем сталкиваются с проблемами, потому что основная форма программы не такая, как они думают.

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

SplashForm := TSplashForm.Create(Application);
SplashForm.Show;
SplashForm.Update; // force update
Application.Initialize;

// Change to this.
ClientData := TClientData.Create(Application);

SplashForm.Update; // force update
Application.CreateForm(TClientMainForm, ClientMainForm);
Application.ShowHint := True;

Application.Run;
ClientMainForm.ServerConnected := false;

// Remove these.
FreeAndNil(ClientMainForm);
FreeAndNil(ClientData);

Вы действительно не должны освобождать объекты, которые вы создали здесь, потому что вы не являетесь их владельцем. Они принадлежат глобальному объекту Application, поэтому пусть он позаботится об их освобождении: удалите два вызова FreeAndNil.

1 голос
/ 01 февраля 2010

Если TClientData - это модуль данных, а TClientMainForm - это форма, то нет (за исключением, возможно, двух вызовов FreeAndNil в конце, которые на самом деле не нужны). Но будь осторожен. Потому что, как говорит Роб Кеннеди в своем посте, Application.CreateForm выполняет другие функции (устанавливает переменную MainForm ), поэтому я бы посоветовал настроить файл проекта в соответствии со следующими правилами:

  1. Создайте все формы, которые вы хотите создать при запуске, используя одиночный вызов для Application.CreateForm - обычно это делается в среде IDE.

  2. Удалите из файла проекта формы, которые вы хотите динамически создавать (по требованию) в вашей программе. (В Project | Options | Forms ...) - переместите их из «Auto-Create Forms» в «Available Forms»

  3. Создайте свои формы в вашем коде, используя TmyForm.Create (Владелец) (и т. Д.) И не с Application.CreateForm (...) . Кроме того, если вы уверены, что освободите форму, то лучше (чтобы ускорить процесс) позвонить TmyForm.Create ( nil ) - iow без владельца.

  4. Если вы хотите выполнить какую-то инициализацию при запуске, вы можете иметь процедуру / метод в файле проекта, привязанном к уже созданному модулю формы / данных, и запускать его до запуска приложения.

Например:

begin 
  Application.Initialize; 
  Application.MainFormOnTaskbar := True; 
  Application.CreateForm(TdmoMain, dmoMain); //<--this is a data module
  Application.CreateForm(TfrmMain, frmMain); //<--this will became the main form
  Application.CreateForm(TfrmAbout, frmAbout);
  //... other forms created here...
  frmMain.InitEngine; //<--initialization code. You can put somewhere else, according with your app architecture
  Application.Run;
end.

Таким образом, у вас будет чистый файл проекта, и вы будете точно знать, какой именно.

НТН

0 голосов
/ 16 февраля 2010

Статья, на которую вы ссылаетесь, неверна.Существует ряд веских причин, по которым вы хотите использовать несколько вызовов Application.CreateForm

1) Модули данных: вы, вероятно, хотите, чтобы они были доступны постоянно.Лучший способ сделать это - Application.CreateForm.Я знаю о приложениях с несколькими тематическими модулями данных, например, Customer, Invoice, Address, чтобы обрабатывать различные области базы данных и аккуратно инкапсулировать функциональность.Все они созданы в .dpr

2) Большие, медленно загружаемые вещи (что само по себе является плохой идеей, но такие вещи случаются и часто наследуются программистами поддержки ...).Переместите время загрузки в запуск приложения точно так же, как ваш пример кода, вместе с обновлением заставки.Пользователи ожидают, что запуск приложений займет некоторое время, благодаря активным усилиям наших коллег, работающих над Microsoft Office, снизить планку ожиданий для остальных из нас:)

Итак,Таким образом, не беспокойтесь, ваш код в порядке - но вы можете потерять материал "FreeAndNil".Тем не менее, небольшие быстрые нажатия типа Dialog лучше всего вызывать:

with TMyform.Create(nil) do
try
  //Setup
  case ShowModal of
    // Whatever return values you care about (if any)
  end;
finally
  Free;
end;

Коротко, мило, точно и минимизирует использование памяти ...

...