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

TdamUIData

Для краткости приведу только свойства и методы, которые относятся к сути вопроса. Списки fFrameList и fFrameStack создаются при создании модуля и разрушаются вместе с ним. Поле fForm заполняется в методе Init().

TdamUIData = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    fForm: TForm;
    fFrameList: TStringList; // созданные фреймы
    fFrameStack: TStringList; // стек отображения
  public
    procedure ShowFrame(AName: string);
    procedure GoBack;
    procedure Init(AForm: TForm);
  end;

procedure TdamUIData.DataModuleCreate(Sender: TObject);
var
  tmpPath: string;
  tmpFileName: string;
  tmpIniFile: TIniFile;
begin
  fFrameList := TStringList.Create;
  fFrameStack := TStringList.Create;
  tmpPath := TPath.Combine(TPath.GetDocumentsPath, BASE_SUBDIR);
  if not TDirectory.Exists(tmpPath) then
    TDirectory.CreateDirectory(tmpPath);
end;

procedure TdamUIData.DataModuleDestroy(Sender: TObject);
begin
  fFrameList.Free;
  fFrameStack.Free;
end;

procedure TdamUIData.Init(AForm: TForm);
begin
  fForm := AForm;
  // задаем папку для хранения файлов БД
  fBasePath := TPath.Combine(TPath.GetDocumentsPath, BASE_SUBDIR);
  if not TDirectory.Exists(fBasePath) then
    TDirectory.CreateDirectory(fBasePath);
end;Code language: Delphi (delphi)

А вот методы навигации рассмотрим подробней. Сейчас они только управляют видимостью фреймов, в дальнейшем в них будет добавлена анимация.

ShowFrame

Сначала отображаемый фрейм ищется в списке уже созданных фреймов fFrameList, а если его там ещё нет, то с помощью репозитория фреймов создается новый экземпляр. Затем в стеке fFrameStack находится предыдущий фрейм и делается невидимым. После чего новый фрейм окончательно помещается на главную форму (Parent := fForm) и делается видимым (Visible := True). После чего проводится его первичная инициализация методом Inint(). Идентификация производится по имени, а для остальных манипуляций используется методы базового класса TfraBaseFrame.

procedure TdamUIData.ShowFrame(AName: string);
var
  i: integer;
  j: integer;
  s: string;
begin
  i := fFrameList.IndexOf(AName);
  if i = -1 then
    i := fFrameList.AddObject(AName, TfraBaseFrame(FrameRep.GetFrame(AName, fForm)));
  fFrameStack.Add(AName);
  if fFrameStack.Count > 1 then // скрываем предыдущий фрейм, если он есть
  begin
    s := fFrameStack.Strings[fFrameStack.Count - 2];
    j := fFrameList.IndexOf(s);
    TfraBaseFrame(fFrameList.Objects[j]).Visible := False;
  end;
  TfraBaseFrame(fFrameList.Objects[i]).Parent := fForm;
  TfraBaseFrame(fFrameList.Objects[i]).Visible := True;
  TfraBaseFrame(fFrameList.Objects[i]).Init;
end;Code language: Delphi (delphi)

GoBack

Чтобы “вернуться назад” нужно найти в списке фреймов последний элемент из стека фреймов и сделать его невидимым. Затем удалить последний элемент из стека. А теперь сделать последний элемент в стеке видимым.

procedure TdamUIData.GoBack;
var
  s: string;
  i: integer;
begin
  if fFrameStack.Count > 1 then
  begin
    s := fFrameStack.Strings[fFrameStack.Count - 1];
    i := fFrameList.IndexOf(s);
    TfraBaseFrame(fFrameList.Objects[i]).Visible := False;
    fFrameStack.Delete(fFrameStack.Count - 1);
    s := fFrameStack.Strings[fFrameStack.Count - 1];
    i := fFrameList.IndexOf(s);
    TfraBaseFrame(fFrameList.Objects[i]).Visible := True;
    TfraBaseFrame(fFrameList.Objects[i]).Update;
  end;
end;Code language: Delphi (delphi)

Ссылки

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *