Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Создание формы в режиме Autoran 
:(
    Опции темы
PsiMagistr
Дата 26.5.2010, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Ребята, наверняка я вам уже надоел со своими вопросами, простите меня, но больше мне не к кому обратиться. Visual Basic с его недо реализацией классов так же похож на ООП  Delphi как торпеда на форель. ))) А пока немножко кода:

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls; //Подключение заголовочных модулей

type
  TForm1 = class(TForm) //Создание класса TForm1
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end; // Конец описания класса

var
  Form1: TForm1; //Создание переменной указателя

implementation

uses Unit2;

{$R *.dfm}



Вот код, который Дельфи создает в самом начале, при запуске проекта. Мы видим добавление заголовочных модулей, создание класса TForm1 и создание переменной-указателя Form1. А кто нибудь видит инициализацию формы? К примеру вызов конструктора Create? Не видите? И не увидите. А между тем он написан. Но код его не здесь. Но достаточно выбрать в меню Дельфи команду: Project/View/Source и вы отыщите в открывшимся окне знакомую строку:

Код

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1); //А теперь - конструктор, я сказал - конструктор, выходи! Ключ на старт!
  Application.Run;
end.


Многое сразу прояснилось. Однако не все. Идем дальше. Закройте наш участок кода, где описан конструктор и добавьте в проект новую форму: 
File/New/Form. Перейдите в код первой (главной)  формы и после слова implementation напишите:

uses Unit2; 

Мы сразу подключили  модуль второй формы в код главной, чтобы удобно было работать. Запустите проект на выполнение. Что мы видим? А ничего особенного. Плавает по экрану главная форма и вот собственно и все. Однако еще не все свершились чудеса! Дело в том, что сейчас, при запуске, создались сразу ДВЕ ФОРМЫ! Наша главная и новодобавленная. Просто она то как раз и невидима. По умолчанию. Хотите убедиться? Закройте окно программы и вернитесь в Дельфи. Найдите вторую форму (Form2) и сделайте ее свойство Visible равным True. Запускайте программу. Теперь у нас две формы и мы их отлично видим. Хорошо ли это, что все добавочные формы рождаются автоматически, сразу при старте программы, (напоминаю: все конструкторы форм можно увидеть, если пройтись по меню Project/View/Source)? Ну в принципе, если у вас в проекте 2-3 формы, включая главную, то ничего страшного нет. Рождаются две-три невидимые добавочные формочки, ждут своего часа (метода show или свойства visible:=true). А вот если у нас в проекте 50-100 форм и все так и норовят запрыгнуть  при старте в оперативную память?! Нда... Несладко. Особенно если все эти формы нам не нужны одновременно. Как же сделать так, чтобы побочные формы не инициализировались автоматически? На самом деле это просто. Закройте программу, вернитесь в среду Дельфи. Выберите команду меню: Project/Options и в появившемся служебном окне среды Дельфи отыщите вкладку Forms. Там вы увидите два списка.  В одном из них (левом) находятся имена обеих наших форм. Правый пустой.  Все формы, находящееся в правом списке инициализируются автоматически. Выделите в левом списке нашу Form2, и нажмите кнопочку с угловой скобочкой вправо. Теперь Form2 оказалась в правом списке.  И это значит, что никакого ее автосоздания не будет. Закройте служебное окошко кнопочкой ОК. Запустите программу на выполнение. По экрану плавает окно главной формы. А где вторая? А ее нет. Нет, она не невидима, ее свойство Visible := True, мы сами сделали его таким еще в начале.  но... Ее просто нет. Она еще не появилась на свет. Сейчас мы попробуем вызвать ее конструктор ручками. Закройте окошко программы и вернитесь в Дельфи.  Отыщите главную форму, добавьте на нее кнопочку, измените ее свойство Caption на 'Рождение формы' Запишите в обработчике Onclick

Код

procedure TForm1.Button1Click(Sender: TObject);
begin
Form2:=TForm2.Create(Form1.Owner);
end;


Form2 - это просто указатель  на будущую форму. Сама она объявлена в модуле второй формы, но модуль главной ее отлично видит, в самом начале мы сделали все подключения. В конструктор передается параметр Owner, указывая на владельца порождаемой формы. В данном случае владелец - Form1. Так что можно писать и просто  Owner.

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

Код

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



Если никакого кода не писать, то параметр Action по умолчанию равен caHide, наша форма просто прячется. Мы же изменили этот параметр на caFree и заставили убраться форму из памяти. 

А теперь вопрос для знатоков:

Если запустить программу и начать жать на кнопку, будут рождаться все новые и новые формы. Так и должно быть. Но вот с чем я так и не разобрался. Указатель на объект-форму у нас только один и это переменная Form2. Туда передается конструктор. Получается, что Form2 всегда указывает на последнюю порожденную форму. Но ведь остальные порожденные формы тоже чувствуют себя неплохо. Их можно активизировать, закрывать. Каким образом это возможно? Ведь указатель всего один.


 









Это сообщение отредактировал(а) PsiMagistr - 27.5.2010, 08:19


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Dom
Дата 26.5.2010, 10:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 3
Всего: 4



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

Если владельца не указывать 
Код

Form2 := TForm2.Create(nil)
то утечек памяти тоже не будет, будет отрабатывать 
Код

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


Это сообщение отредактировал(а) Dom - 26.5.2010, 10:59
PM MAIL   Вверх
PsiMagistr
Дата 26.5.2010, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1




Спасибо большое, но 

Не совсем понял. Получается что владелец имеет  указатели от всех порожденных форм, сколько бы их не было, несмотря на то, что фактически указатель всего один - Form2.




--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Dom
Дата 26.5.2010, 11:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 3
Всего: 4



Дополню. Утечек памяти в последнем случае не будет если закрывать все эти новые формы самостоятельно ручками. Если же закрыть главное окно приложения Form1, когда есть еще открытые экземпляры Form2, то утечки будут.
Вроде бы так...
PM MAIL   Вверх
PsiMagistr
Дата 26.5.2010, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



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

var Form2:TForm2

И  этим одним указателем управляется множество новорожденных форм. Хотя по идее он указывает только на последнюю рожденную:

Form2:=TForm2.Create(Form1.Owner);

Итак единственный указатель указывает на последнюю форму.

Но остальные старенькие тоже неплохо управляются (сворачиваются, закрываются реагируют на щелчки).

 Кто в этот момент указывает на них?



--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Dom
Дата 26.5.2010, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 3
Всего: 4



Эмм, ну почему же указатель всего один? Каждый раз при вызове TForm2.Create создается новый указатель.
PM MAIL   Вверх
PsiMagistr
Дата 26.5.2010, 11:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Да? А как же он появляется? Я всегда думал что объявленный в модуле дочерней формы  указатель  Form2 единственный.  Ведь по идее указатели такие же переменные кто то их должен объявить? Или как.


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
kami
Дата 26.5.2010, 11:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Не нужно смешивать указатель на экземпляр формы и область памяти, на которую ссылается этот указатель.
Сразу после создания формы указателю на нее можно присвоить nil (более того, можно вообще без переменной-указателя обойтись), но область памяти, выделенная при создании формы/любого другого объекта от этого никуда не денется, а именно в ней (выделенной под форму памяти) содержатся все поля формы. (реализация методов, afair, имеется в одном экземпляре, сколько бы таких форм мы ни создали). Только при уничтожении формы выделенная под нее память будет возвращена менеджеру памяти программы.
PM MAIL WWW   Вверх
PsiMagistr
Дата 26.5.2010, 11:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Спасибо, ками. Итак выделенная память у нас есть. Но мы создали 10 форм. Память выделена для первой формы.  И для второй и для десятой тоже. Но что то же должно  указывать на эту конкретную область. К ней же надо как то обращаться. Ну один указатель у нас есть. Но вот откуда берутся остальные девять штук?

Это сообщение отредактировал(а) PsiMagistr - 26.5.2010, 11:33


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Dom
Дата 26.5.2010, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 3
Всего: 4



Ну про детали работы с памятью не расскажу, не знаю.
Должно происходить примерно следующее. При создании объекта создается указатель на него. А выражение Form2 := TForm2.Create(Form1.Owner) всего лишь присваивает этот адрес переменной Form2.
PM MAIL   Вверх
PsiMagistr
Дата 26.5.2010, 11:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Именно. Вот эта то переменная- указатель указывает на адрес памяти последней созданной формы. Но остальные тоже не висят в памяти балластом. Ими управлять спокойно можно. А вот что дает возможность управления? Или при create создается какой то дополнительный указатель?

Это сообщение отредактировал(а) PsiMagistr - 26.5.2010, 11:42


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
kami
Дата 26.5.2010, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(PsiMagistr @  26.5.2010,  11:32 Найти цитируемый пост)
Но вот откуда берутся остальные девять штук?

Ниоткуда smile
В каждое событие, каждый метод любого компонента (и формы тоже) неявно передается указатель Self (сам, я).
Поэтому мы имеем возможность писать в событии формы (указатель на процедуру-обработчик события хранится в выделенной под компонент памяти, т.к. является одним из его полей), например,
Код

Caption:='12343455';
 среда поймет, что это идентично коду
Код

Self.Caption:='12343455';

В противном случае действительно нужно было бы хранить валидные указатели на все созданные компоненты самому.
PM MAIL WWW   Вверх
PsiMagistr
Дата 27.5.2010, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Спасибо, большое, kami.

И только я подумал, что понял все-все-все, как вдруг...

Часть вторая. Утечка памяти или Муки ООП


Сегодня утром столкнулся с совершенно неожиданным для меня результатом.

1) Создайте проект. 
2) Добавьте в проект еще две формы.

Итого у нас Form1, Form2, Form3.

3) Отключите автосоздание Form2 и Form3. Свойство Visible обеих форм сделайте равным True.

 Автосоздаваться у нас будет только одна форма (Form1) Остальные будем создавать динамически.

4) Откройте окно кода Form1  Подключите к модулю Form1 модуль Form2 Для этого после ключевого слова implementation  добавьте:

uses Unit2;

 На форме Form1 нарисуйте кнопку. Смените ее Caption на "Создать окно". Запишите в обработчик щелчка:

Код

procedure TForm1.Button1Click(Sender: TObject);
begin
Form2:= TForm2.Create(Form1.Owner); 
end;


Мы динамически создаем Form2

Теперь перейдите в код Form2. Добавьте после раздела implementation   модуль третей формы:

uses Unit3;


 В обработчике Close запишите:

Код

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree; //Разрушение формы-объекта при закрытии.
end;


На форму Form2 добавьте кнопку. Смените ее Caption на "Создание второй формы".

Запишите в обработчик OnClick;

Код

procedure TForm2.Button1Click(Sender: TObject);
begin
Form3 := TForm3.Create(Form2.Owner); //Внимание. Вы видите как вторая форма рождает третью форму и становится ее владельцем.
end;


Добавьте в обработчик Close третьей формы:

Код

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


Запустите программу. Нажмите на кнопку. Породите вторую форму. Нажмите на кнопку второй формы и от второй породите третью...

Итак третья форма рождена от второй Вторая является ее владельцем. НО...


Закройте вторую форму. Владелец разрушен - сработало caFree обработчика-закрытия.

Вот только третья форма дочерняя осталась на экране. Ай как не хорошо. Ай плохо-плохо.... Как же так??? Ведь она должна разрушиться...


Это сообщение отредактировал(а) PsiMagistr - 27.5.2010, 10:40


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
kami
Дата 27.5.2010, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(PsiMagistr @  27.5.2010,  10:29 Найти цитируемый пост)
Вы видите как вторая форма рождает третью форму и становится ее владельцем.

Неправда Ваша (с) чье-то.
Мы видим, что владельцем(Owner-ом) формы становится владелец текущей формы (Form1.Owner и Form2.Owner - владелец первой и второй форм). Владельцем первой формы (MainForm) является Application, соответственно владельцем второй становится тоже он. С третьей та же история. Чтобы владельцем создаваемой формы стала наша, текущая форма, при нажатии на кнопку нужно писать
Код

Form3:=TForm3.Create(Self);


Цитата(PsiMagistr @  27.5.2010,  10:29 Найти цитируемый пост)
Как же так??? Ведь она должна разрушиться...

Поменяйте параметр в Create и всё встанет на свои места.

Это сообщение отредактировал(а) kami - 27.5.2010, 12:48
PM MAIL WWW   Вверх
PsiMagistr
Дата 27.5.2010, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



kami,  Благодарю вас сердечно. Вы мне глаза открыли.

Стало быть Self в строке

Код

Form3:=TForm3.Create(Self); 


относится не к порождаемой третьей форме. Это Self текущей второй формы.

Правильно ли я Вас понял?

P.S. Огромное спасибо за внимание.


Допустим у нас в проекте только две формы. MainForm и Form2. Есть ли разница при запуске конструктора:

Код

Form2:=TForm2.Create(MainForm.Owner); 


и

Код

Form2:=TForm2.Create(Self); 


Как я понимаю, в первом случае владельцем второй формы становится владелец  MainForm (объект Application), а во втором сама MainForm





Это сообщение отредактировал(а) PsiMagistr - 27.5.2010, 13:46


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1706 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.