IT-Блог о программировании и операционных системах

Исключите всё элементы из Auto Create Forms, кроме главной формы

Очень часто, особенно при разработке больших приложений приходится задействовать дополнительные формы (формы настроек программы, формы прогресса операций и т.д.). По дефолту, все они создаются автоматически при запуске приложения и висят в памяти ожидая от вас методы Show или ShowModal, дабы показать свои толстые морды. Как вы понимаете, они не только увеличивают время загрузки программы, но и расходуют некоторый объём оперативной памяти машины, что приводит к тормознутости ваших разработок, особенно когда машина и так не очень мощная. Вместо того, чтобы грузить все формы сразу, следует создавать их по мере необходимости, а уже потом показывать пользователю.

В файле проекта убирайте всё, что не относится к созданию главной формы. Например, вот так:
Application.Initialize;
Application.CreateForm(TForm1, Form1);
// Application.CreateForm(TForm2, Form2);
// Application.CreateForm(TForm3, Form3);
// Application.CreateForm(TForm4, Form4);
// Application.CreateForm(TForm5, Form5);
Application.Run;

А остальные формы создавайте только по мере необходимости. Например, так:
procedure TForm1.ShowAboutBox();
begin
 Application.CreateForm(TForm2, Form2);
 Form2.Show;
end;

К тому же, редко используемые формы, такие как форма “О программе…” желательно вообще освобождать при закрытии методом Free и обнулять значением nil. Для чего – ясно. Стоит заметить, что в таких случаях, как вы наверное уже догадались, новая форма будет создаваться вновь и вновь, при каждом вызове метода ShowAboutBox. Я обычно в таких случаях просто затеняю ту кнопку или другой контрол, который вызывает метод (что конечно не совсем по правилам прилежного программирования), однако вы можете использовать примерно следующюю конструкцию:
if not Assigned(Form2) then 
 Application.CreateForm(TForm2, Form2);
Form2.Show;

Итак, обрисовывается полная картина использования таких форм. На примере нашей формы вывода информации о программе, привожу следующий код:
procedure TMainForm.AboutButtonClick(Sender: TObject);
begin
 Self.ShowAboutBox;
end;

procedure TMainForm.ShowAboutBox;
begin
 if not Assigned(AboutBox) then Application.CreateForm(TAboutBox, AboutBox);
 AboutBox.Show;
end;

procedure TAboutBox.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Self.Free;
 AboutBox:=nil;
end;


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

4 комментария:

  1. Вынужден с Вами не согласиться.
    Управление временем жизни объекта должно происходить в рамках одного контекста. В данном случае в методе TMainForm.ShowAboutBox.
    Вызов метода Free и присваивание nil переменной вне метода TMainForm.ShowAboutBox делает использование объекта AboutBox менее понятным, к примеру, не до конца ясно, что вернет Assigned(AboutBox) в данный конкретный момент времени.
    ИМХО, использование следующего кода является более предпочтительным:

    procedure TMainForm.ShowAboutBox;
    var
    AboutBox: TAboutBox;
    begin
    AboutBox := TAboutBox.Create(Application);
    try
    AboutBox.Show;
    finally
    FreeAndNil(AboutBox);
    end;
    end;

    ОтветитьУдалить
  2. Анонимный20 мая 2010 г., 2:21

    Конструкция:
    try
    AboutBox.Show;
    finally
    FreeAndNil(AboutBox);
    end;
    посмотреть на форму AboutBox не даст - AboutBox сразу после показа ликвидируется.
    Как минимум надо вместо Show поставить ShowModal.

    А вот что вернет Assigned(AboutBox) - интересно! Вот :
    ...
    Assigned(P)
    ...
    Assigned returns False if P is nil, True otherwise.
    Помоему всё нормально!

    FreeAndNil немного читабельнее чем
    Self.Free;
    AboutBox:=nil;

    а делает почти тоже самое только с лишним вызовом... :
    procedure FreeAndNil(var Obj);
    var
    Temp: TObject;
    begin
    Temp := TObject(Obj);
    Pointer(Obj) := nil;
    Temp.Free;
    end;

    ОтветитьУдалить
  3. >> opportune-fl
    >> Управление временем жизни объекта должно >>происходить в рамках одного контекста

    Совершенно верно, спасибо. На самом деле за это меня уже несколько раз "били по рукам".

    >>Конструкция:
    >>посмотреть на форму AboutBox не даст - >>AboutBox сразу после показа ликвидируется.
    >>Как минимум надо вместо Show поставить >>ShowModal.

    Правильно. Но если форма предпологает использование драг&дрод c другой формой например, такой метод выходом назвать нельзя. Или я ошибаюсь?

    ОтветитьУдалить
  4. Уже давно пользуюсь данным приемом. Никаких проблем не возникало.

    ОтветитьУдалить