Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
Да нет, все-таки подменяет:) То есть магия заключатся в неявном вызове компилятором NewInstance при вызове конструктора как метода класса, а Application.CreateForm делает то-же самое, но явно, да еще вклинивая туда TComponent(Reference) := Instance. Так что все-таки - подменяет:)))
18-07-2008 03:27 | Комментарий к предыдущим ответам
>>> Application.CreateForm подменяет эту магию компилятора
Только наверное не подменяет, а использует. Т.е. пользуется возможностью использовать конструктор и так и сяк.
Отличие двух вариантов в том, что в одном случае сперва выделяется память, а потом уже запускается конструктор, а в другом - что выделение памяти берёт на себя конструктор.
Более строго говоря, метод Application.CreateForm вначале создает экземпляр объекта, потом присваивает переменной ссылку на него, и только после этого производит инициализацию объекта, чем по сути дела и занимается дельфийский конструктор, а настоящим конструктором является NewInstance, который и создает реально экземпляр объекта и производит его начальную инициализацию. А constructor было-бы, на мой взгляд, логичнее назвать Initialize, это бы точнее отразило его назначение.
Возможно стоит упомянуть, что при вызове конструктора как метода класса имеет место т.н. "Compiler magic". Компилятор неявно вставляет сначала вызов NewInstance, а уже после этого вызывает сам конструктор, передав ему только-что созданный объект.
А Application.CreateForm подменяет эту магию компилятора своим поведением с главной целью - присвоить переменной ссылку на новый объект до его инициализации.
Отличие двух вариантов в том, что в одном случае сперва выделяется память, а потом уже запускается конструктор, а в другом - что выделение памяти берёт на себя конструктор.
1. Application.CreateForm(Tf_options, f_options);
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
Instance: TComponent;
begin
Instance := TComponent(InstanceClass.NewInstance); // В этот момент для объекта формы выделяется память
TComponent(Reference) := Instance; // Теперь объект записывается в Instance, в нашем случае - в переменную f_options.
// К этому момент f_options содержит форму, но она ещё не инициализирована
if (FMainForm = nil) and (Instance is TForm) then
SetCreatingMainForm(TControl(Instance));
try
try
Instance.Create(Self); // Здесь вызывается конструктор, он инициализирует форму, создаёт компоненты и т.п.
// Сразу после конструктора срабатывает AfterConstruction, который вызывает событие OnCreate. В Oncreate ваш код может оперировать с f_options, т.к. ссылка в неё была вписана выше.
except
TComponent(Reference) := nil;
raise;
end;
...
2. f_options := Tf_options.Create(Application);
Очевидно, что здесь сначала выполняется Tf_options.Create(Application), а затем - операция присвоения (наоборот нельзя - ведь тогда бы нечего было бы присваивать).
Tf_options.Create(Application);
Здесь вызывается конструктор, он выделяет память под объект (форму), инициализирует её, загружает компоненты и т.п.
Сразу после конструктора вызывается AfterConstruction, он вызывает событие OnCreate. Ваш код не может обратиться к форме через f_options, т.к. сейчас она равна nil - ведь её же никто не инициализировал. Чтобы кто-то обратился к форме, мы должны явно передать ему ссылку, либо же вручную её вписать, например так:
procedure TForm1.FormCreate(Sender: TObject);
begin
f_options := Self;
// ... другой код теперь может обратиться к форме через f_options
end;
f_options := {созданная форма}
И только после выхода из AfterConstruction выполняется присваивание. Теперь f_options содержит объект формы и мы можем обратиться к форме через f_options.
>>> пытпюсь их присвоить компонентам на форме
Вот в этот момент у вас AV и есть.
>>> А как быть в такой ситуации: в onCreate вызывается процедура, в коде которой идет обращение к f_options и данная процедура находится в другом юните?
Например:
procedure Tf_options.FormCreate(Sender: TObject);
begin
Load(Self);
end;
...
uses f_options;
procedure Load(AForm: Tf_options);
begin
AForm.TreeOptions.Items.Item[0].Text:='test';
end;
Или:
procedure Tf_options.FormCreate(Sender: TObject);
begin
Load(Self);
end;
...
uses f_options;
procedure Load(AForm: TForm);
begin
if AForm is Tf_options then
with Tf_options(AForm) do
begin
TreeOptions.Items.Item[0].Text:='test';
end;
end;
Покажите, что такое TreeOptions и LangPlug?
TreeOptions это TTreeView, а LangPlug- грубо говоря, массив со строковыми значения (я туда гружу строчки из файла, а потом,в момент создания формы, пытпюсь их присвоить компонентам на форме).
Мне кажется, что какой-то объект не создан у Вас, но используется в OnCreate();
Попробуйте поставить там ShowMessage(); и посмотреть что выйдет.
У меня вообще ощущение, что создается только форма, потом вызывается onCreate, а потом уже создаются компоненты на форме%)
TreeOptions.Items.Item[] - а сами Item-ы созданы?
да
то в OnCreate формы имеет место обращение к самому себе не через Self, а через переменную f_optionsтак и есть... А как быть в такой ситуации: в onCreate вызывается процедура, в коде которой идет обращение к f_options и данная процедура находится в другом юните?
Типа:
procedure Tf_options.FormCreate(Sender: TObject);
begin
Load;
end;
...
uses f_options;
procedure Load;
begin
f_options.TreeOptions.Items.Item[0].Text:='test';
end;
Если при AutoCreate работало, а после закомментирования перестало, то в OnCreate формы имеет место обращение к самому себе не через Self, а через переменную f_options. Если это так, то при таком коде
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(F_Options) then
Application.CreateForm(Tf_options, f_options);
f_options.show;
end;
AV должно исчезнуть. Но лучше объектам не обращаться к самим себе через внешнюю переменную.
Странно, сделал -- все нонрмально работает.
Мне кажется, что какой-то объект не создан у Вас, но используется в OnCreate();
Попробуйте поставить там ShowMessage(); и посмотреть что выйдет.
Ну так поставьте в OnCreate точку останова, и медленно пройдите отладчиком, контролируя все переменные и заходя во все функции. Где то увидите обращение к переменной, равной nil.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.