我正在尝试创建一个表单实例并传递一个必须特定于该实例的参数。
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是sucn实例之一的变量。当我打开实例时,我就是这样:
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,如果稍后我要为窗体调用某些程序,则会收到AV错误。在逐步调试中观看CharacterScreen变量时,它被描述为nil。
所以我的问题是:创建表单实例的正确方法是什么(以便以后我可以创建第二个实例,依此类推)?另外,这是存储变量ViewedData实例的正确方法,该实例对于表单的每个实例必须是唯一的吗?
答案 0 :(得分:4)
问题在于您从构造函数中调用Free,因此当您关闭表单时,实例将变得不可访问。
您可以在表单中添加静态方法,然后从其他表单中调用它。
最佳做法是删除全局表单变量,以便调用代码必须声明一个局部变量(当您创建同一表单的多个实例时,该变量将变得明显)。 在此示例中,我将构造函数设为私有,因此只能在该单元外部调用execute方法。
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;
现在您可以这样调用表单:
var CharacterScreen : TDataForm;
CharacterScreen := TDataForm.Execute(@Data,'Page 1');
try
// do something with CharacterScreen when it has been closed
finally
CharacterScreen.Free;
end;
** 更新 **
现在,如果我是你,我会做类似的事情(伪代码,我想你会明白的):
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;
现在调用代码可以看起来像这样
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;