Reputation: 39
I'm trying to create an instance of a form and pass a parameter, that has to be specific to that instance.
type
TDataForm = class(TForm)
{ Some components}
{ Some procedures }
constructor Create(AOwner: TComponent; Data: PData; Page: String); reintroduce;
private
{ Private declarations }
public
{ Public declarations }
ViewedData: PData;
end;
var CharacterScreen: TDataForm;
implementation
CharacterScreen is a var for one of sucn instances. When i'm opening than instance, i'm doing it like this:
constructor TDataForm.Create(AOwner: TComponent; Data: PData; Page: String);
begin
inherited Create(nil);
ViewedData:=Data;
if Page='Stats' then CharPageControl.TabIndex:=0;
if Page='Equipment' then CharPageControl.TabIndex:=1;
if Page='Effects' then CharPageControl.TabIndex:=2;
if Page='Statistics' then CharPageControl.TabIndex:=3;
ShowModal;
Free;
end;
CharacterScreen:=TDataForm.Create(nil,@Data,'Page 1');
Howewer, if later i'm calling some procedure for than form, i get an AV error. When watching CharacterScreen variable in step-by-step debug, it's described as nil.
So my question is: what is the correct way to create an instance of a form (so that later i can create a second instance and so on)? Also, is it a correct way to store an instance of variable ViewedData, that has to be unique to each instance of a form?
Upvotes: 0
Views: 274
Reputation: 11860
The problem is that you call Free from the constructor, so the instance will become inaccessible when you close the form.
You can add a static method to the form and call that from other forms.
it is best practice to remove the global form variable so that the calling code must declare a local variable (will become apparent when you create multiple instances of the same form). In this example, I made the constructor private, so that only the execute method can be called outside this unit.
type
TDataForm = class(TForm)
{ Some components}
{ Some procedures }
private
{ Private declarations }
ViewedData: PData;
constructor Create(AOwner : TComponent);
public
{ Public declarations }
class procedure Execute(Data: PData; APage: String);
end;
implementation
class function TDataForm.Execute(Data: PData; APage: String) :TDataForm;
begin
Result := TDataForm.Create(nil);
Result.ViewedData := PData;
if APage='Характеристики' then Result.CharPageControl.TabIndex:=0 else
if APage='Экипировка' then Result.CharPageControl.TabIndex:=1 else
if APage='Эффекты' then Result.CharPageControl.TabIndex:=2 else
if APage='Статистика' then Result.CharPageControl.TabIndex:=3;
Result.ShowModal;
end;
constructor TDataForm.Create(AOwner: TComponent);
begin
inherited Create(nil);
end;
now you call your form like this:
var CharacterScreen : TDataForm;
CharacterScreen := TDataForm.Execute(@Data,'Page 1');
try
// do something with CharacterScreen when it has been closed
finally
CharacterScreen.Free;
end;
** UPDATE **
Now If I were you I would do something like this (pseudo code, I assume you'll get the idea) :
Unit character;
type
TCharacterData = class
public
// some public fields
end;
...
Unit EditCharacter;
type
TDataForm = class(TForm)
procedure OnShow(Sender : TObject);
public
class procedure Execute(Data : TCharacterData) : Boolean;
end;
implementation;
class function TDataForm.Execute(var Character: TCharacter) : Boolean;
var Frm: TDataForm ;
begin
Result := False;
Frm:= TDataForm.Create(nil);
try
Frm.Character := Character;
Frm.ShowModal;
Result := Frm.ModalResult = mrOK;
finally
Frm.Free;
end;
end;
procedure TDataForm.OnShow(Sender : TObject);
begin
if Character = TWizardCharacter then Frm.CharPageControl.TabIndex:=0 else
if Character = TBarbarianCharacter then Frm.CharPageControl.TabIndex:=1
... //etc
end;
now the calling code can look like this
var Character : TCharacter;
...
Character := TWizardCharacter.Create;
...
// user wants to edit character
procedure EditCharacter;
begin
if TDataForm.Execute(Character) then
begin
// user has modified character, act accordingly
end;
end;
Upvotes: 4