Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Закрытие MDIChild-формы  [new]
client6aac
Member

Откуда:
Сообщений: 16
Пишем MDI приложение.
В нем есть базовая форма для всех MDIChild-фор, пусть TMdiBaseForm, от которой наследуются все остальные дочерние формы;

При закрытии дочерних формы не сворачиваем их, а именно закрываем:

procedure TMdiBaseForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;


Все формы создаются типовым способом:

  if Assigned(frmMdiChildren1) 
    then frmMdiChildren1.BringToFront
    else frmMdiChildren1 := TfrmMdiChildren1.CreateMDI(Application);


Все работает как надо, до момента закрытия формы.
После этого переменная frmMdiChildren1 остается ненулевая и форма повторно не создается.
Так вот вопрос: как занулить переменную формы после ее закрытия?
28 фев 19, 12:24    [21821597]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
zinpub
Member

Откуда:
Сообщений: 342
client6aac,

frmMdiChildren1:= nil;
28 фев 19, 12:40    [21821623]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
goldmi45
Member

Откуда:
Сообщений: 1115
client6aac,

function TMainForm.CheckMDIChild(Sender: TForm): Boolean;
var
  i: Integer;
begin
  Result := False;
  for i := 0 to (MDIChildCount - 1) do
    if MDIChildren[i] = Sender then
    begin
      Result := True;
      exit;
    end
    else
      Result := False;
end;


Использование
  if CheckMDIChild(frmMdiChildren1) then
    frmMdiChildren1.Show
  else
    frmMdiChildren1 := TfrmMdiChildren.Create(Self);  
28 фев 19, 12:41    [21821626]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
DimaBr
Member

Откуда:
Сообщений: 10922
client6aac
После этого переменная frmMdiChildren1 остается ненулевая и форма повторно не создается.


А где место в котором вы обнуляете переменную ? Зачем вообще существует переменная frmMdiChildren1 ?
28 фев 19, 12:47    [21821634]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
client6aac
Member

Откуда:
Сообщений: 16
DimaBr
А где место в котором вы обнуляете переменную?

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

DimaBr
Зачем вообще существует переменная frmMdiChildren1 ?

Для того, что бы понять создавалась форма ранее или нет. Если будет создано стопитцот разных окошек и искомое потеряется где-то в самом низу, то клацнув в главном меню на пунктик вызова этого окна мы или выведем его наверх (если оно было ранее создано), либо создадим.

В общем-то, нужное решение было дано в третьем посте, за что goldmi45 отдельное спасибо. Наверное тему можно закрывать
28 фев 19, 13:02    [21821654]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
zinpub
Member

Откуда:
Сообщений: 342
client6aac,

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;

  Form2 := nil;
end;


Открываем

procedure TForm1.btnClick(Sender: TObject);
begin
  if Assigned(Form2) then
    Form2.Show
  else
  begin
    Application.CreateForm(TForm2, Form2);
    Form2.Show;
  end;
end;
28 фев 19, 13:06    [21821659]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
zinpub
Member

Откуда:
Сообщений: 342
Но это - корявый метод...

Лучше закрывать\открывать "Главной формой"
28 фев 19, 13:07    [21821660]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
client6aac
Так вот вопрос: как занулить переменную формы после ее закрытия?


Удалить эту переменную вообще.
Она не нужна.

Реестр существующих окон держать в другом виде, например

 Type MyMDIClass = class of TMdiBaseForm;
Var   MyMDIForms: TDictionary<MyMDIClass, TMdiBaseForm>


Ну и не забывать оттуда удалять закрываемые формы.

P.S. именно такой реестр на самом деле редко практичен: он не позволяет открывать НЕСКОЛЬКО окон одного класса. Впрочем, как и переменная "frmMdiChildren1" не может содержать несколько указателей на несколько окон сразу.

А в реальности часто по другому. Например в браузере открыто несколько разных веб-страничек, в Excel открыто несколько разных файлов: класс один и тот же, а окон много: уникальный идентификатор окна состоит не только из класса, но и ещё каких-то данных.
28 фев 19, 13:08    [21821662]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
client6aac
Member

Откуда:
Сообщений: 16
zinpub
client6aac,

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;

  Form2 := nil;
end;

[/src]


Не годится... Action := caFree; делаем в базовой форме, которая ничего не знает про Form2

Arioch
В текущей логике приложения как раз и нужно открытие окошек в единственном экземпляре.
Но за наставление на путь истинный - спасибо!
28 фев 19, 13:18    [21821675]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
goldmi45
Member

Откуда:
Сообщений: 1115
Arioch,

Зачем создавать то, что уже есть?

MDIChildren и MDIChildCount
28 фев 19, 13:20    [21821678]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
krapotkin
Member

Откуда: Екатеринбург
Сообщений: 658
список MDI окон у нас по факту есть
но держать ссылки на формы в своем ObjectList(OwnObjects=FALSE!!!) никто не мешает
при закрытии нужно пробегать по нему и удалять из него ссылку на удаляемую форму

вопрос именно - для чего нам этот список
более практичным выглядит вариант когда это список моих объектов, которые содержат всякие данные и В ТОМ ЧИСЛЕ ссылку на форму...
28 фев 19, 13:21    [21821682]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
client6aac
Member

Откуда:
Сообщений: 16
Arioch
Вот только что созрела мысль, что в Вашем варианте с Дикшионари я тоже не очень понимаю как удалять Айтем из словаря при закрытии формы при условии, что все это должно быть реализовано в базовой форме
28 фев 19, 13:22    [21821683]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
DimaBr
Member

Откуда:
Сообщений: 10922
А две одинаковые формы (одного типа) не могут быть созданы ?
28 фев 19, 13:22    [21821684]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
client6aac
Member

Откуда:
Сообщений: 16
DimaBr
А две одинаковые формы (одного типа) не могут быть созданы ?

нет, при попытке создания второго экземпляра формы, нужно вывести наверх уже имеющийся
28 фев 19, 13:25    [21821688]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
goldmi45
client6aac,

function TMainForm.CheckMDIChild(Sender: TForm): Boolean;
var
  i: Integer;
begin
  Result := False;
  for i := 0 to (MDIChildCount - 1) do
    if MDIChildren[i] = Sender then
    begin
      Result := True;
      exit;
    end
    else
      Result := False;
end;


Или проще

function TMainForm.CheckMDIChild(Sender: TForm): Boolean;
begin
  Result := MyFormsRegistry.Contains(Sender as TMdiBaseForm);
end;


http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Generics_Collections_TList_Contains.html

Но вообще привязывать реестр (реестры) открытых окон к TMainForm - стрёмная идея.
Потом если понадобиться распутать - то хрен распутаешь, спагетти зависимостей нарастёт.

Type TMdiBaseForm = class
...
private
    FRegistry: TList<TMdiBaseForm>; 
   // может быть один синглтон на всю программу, или несколько (разные открытые проекты-странички-файлы)
....
public
  procedure BeforeDestruction; Override;
  property MDIRegistry: TList<TMdiBaseForm> write RegisterInNewRegistry;
....

procedure TMdiBaseForm.BeforeDestruction; 
begin
   MDIRegistry := nil;
   inherited;
end;

procedure TMdiBaseForm.RegisterInNewRegistry(const NewReg: TList<TMdiBaseForm>); 
begin
   if NewReg = FRegistry then exit;
   if nil <> FRegistry then FRegistry.Remove(Self);
   if nil <> NewReg then NewReg.Add(Self);   
   FRegistry := NewReg;
end;

.....

  LMyNewForm := TMyMDIxxxxForm.Create( ...... );
  LMyNewForm.XXX := yyy;
  LMyNewForm.AAA := bbb;
  LMyNewForm.MDIRegistry := MyProjectWindows;
  LMyNewForm.Show;
28 фев 19, 13:25    [21821689]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
client6aac
Member

Откуда:
Сообщений: 16
Arioch,
я не пойму как это все делать из БАЗОВОЙ формы:)
28 фев 19, 13:27    [21821692]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
goldmi45
Arioch,

Зачем создавать то, что уже есть?

MDIChildren и MDIChildCount


1) лаконичнее. Одна строка - вызов стандартной функции TList<t>.Contains гораздо меньше, чем расписанный вами if с циклами. Следовательно, меньше шансов тупой ошибки.

2) гибче. Например, в дальнейшем нужно будет иметь несколько MDI-Parent окон. Или с MDI будет переход на что-то другое (табы, докающиеся плавающие окна, ...)
28 фев 19, 13:27    [21821693]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
zinpub
Member

Откуда:
Сообщений: 342
client6aac
zinpub
client6aac,

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;

  Form2 := nil;
end;

[/src]


Не годится... Action := caFree; делаем в базовой форме, которая ничего не знает про Form2


Ну
Sender:= nil;
28 фев 19, 13:30    [21821700]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
client6aac
я не пойму как это все делать из БАЗОВОЙ формы:)


1) пробросить в базовую формы ссылку на содержащий её реестр
2) иметь один единственный реестр в приложении - глобальную переменную
28 фев 19, 13:30    [21821701]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
client6aac
Не годится... Action := caFree; делаем в базовой форме, которая ничего не знает про Form2


так From2 тут явно один из потомков базовой формы, то же самое, что frmMdiChildren1
28 фев 19, 13:32    [21821702]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
zinpub
Member

Откуда:
Сообщений: 342
Но Arioch прав, гораздо лучше реестр окон, в который можно добавить собственные свойства\методы... итд
28 фев 19, 13:32    [21821703]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
zinpub
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;

  Form2 := nil;
end;[/src[

Ну [SRC pascal]Sender:= nil;


Зачем? переменная Sender перестаёт существовать через мгновение, когда ты выходишь из процедуры!
28 фев 19, 13:33    [21821706]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
Arioch
procedure TMdiBaseForm.RegisterInNewRegistry(const NewReg: TList<TMdiBaseForm>); 
begin
   if NewReg = FRegistry then exit;
//   if nil <> FRegistry then FRegistry.Remove(Self);
   if nil <> FRegistry then begin
     FRegistry.Remove(Self);
     FRegistry := nil;
   end;
   if nil <> NewReg then NewReg.Add(Self);   
   FRegistry := NewReg;
end;


Вот так лучше.
28 фев 19, 13:36    [21821709]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
zinpub
Member

Откуда:
Сообщений: 342
Arioch
zinpub
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;

  Form2 := nil;
end;[/src[

Ну [SRC pascal]Sender:= nil;


Зачем? переменная Sender перестаёт существовать через мгновение, когда ты выходишь из процедуры!


Тьфу... Да! затупил...
28 фев 19, 13:36    [21821710]     Ответить | Цитировать Сообщить модератору
 Re: Закрытие MDIChild-формы  [new]
Arioch
Member

Откуда:
Сообщений: 10598
krapotkin
более практичным выглядит вариант когда это список моих объектов, которые содержат всякие данные и В ТОМ ЧИСЛЕ ссылку на форму.


после чего этот список начинает расти, а либо поиск, либо удаление объектов в массиве - операции дорогие

свалить ВСЕ объекты в одну кучу - спорное решение.
28 фев 19, 13:38    [21821716]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Delphi Ответить