1.5 改造主窗体的代码
在上一节中我们通过创建一个子窗体的父窗体来规范和简化子窗体的代码,但我们却为此使得主窗体的代码增加了不少,而且要创建一个子窗体时还要增加不少的代码。这样的效果还不是我们想得到的。现在让我们来看看如何来简化主窗体的代码
procedure TfrmMain.mnFormCClick(Sender: TObject);
var
frm : TCustomChildForm;
begin
frm := SearchMDIChild(Sender);
if frm = nil then
begin
frm := TfrmChildC.Create(Application); //注一
AddMDIChildList(Sender, frm);
end;
frm.Show;
end;
对于每一个不同的子窗体,只是(注一)的代码有所不一样而已,因此要简化这个过程,我们必须要解决这个不同的地方。但这里有别于一般的情况,这里会改变的地方是一个“类对象”,因此我们要解决的是处理类对象的变量。我们可以参考一下 MDI_Tutorial.dpr中,我们经常删除掉的代码:
Application.CreateForm(TfrmChildD, frmChildD);
在这行代码中,CreateForm函数能把类作为函数,并将其创建成一个实例,最后赋值给一个变量,我们如果也能实现类似的函数就可以解决我们遇到的问题了
我们看一下CreateForm是如果工作的,打开VCL中的Forms.pas,找到以下函数
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
Instance: TComponent;
begin
Instance := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := Instance;
try
Instance.Create(Self);
except
TComponent(Reference) := nil;
raise;
end;
if (FMainForm = nil) and (Instance is TForm) then
begin
TForm(Instance).HandleNeeded;
FMainForm := TForm(Instance);
end;
end;
红色的地方就是我们想要的内容,我们参照上面的代码,可以写出以下的代码:
TCustomChildFormClass = class of TCustomChildForm;
……
function TfrmMain.CallChildFrom(Sender: TObject;
AClass: TCustomChildFormClass): TCustomChildForm;
begin
result := SearchMDIChild(Sender);
if result = nil then
begin
result := TCustomChildForm (AClass.NewInstance);
result.Create(Application);
AddMDIChildList(Sender, result);
end;
result.Show;
end;
procedure TfrmMain.mnFormCClick(Sender: TObject);
begin
CallChildFrom(Sender, TfrmChildC);
end;
至此,我们就简化了每一个Form的创建代码了,这样十分有利于我们新加窗体的显示,但现在主窗体看起来也十分杂乱,我们也采用与子窗体类似的方式,创建一主窗体的父窗体的方式去把这样控制代码进行划分,这样就不会杂乱了。
我们把MainForm.pas另存为 MainFormDefine.pas,然后将这个frmMain改名为CustomMainForm,改好后就重新派生一个frmMain出来,可以用:
File->New->Other->Inheritable Items->CustomChildForm
最后在MDI_Tutorial.pas中将 Application.CreateForm(TCustomMainForm, CustomMainForm);语句删除,这样就可以了。
同样,可能你会觉得现在那些文件位置放得不甚理想,所以我们在文件目录中再创建一个common的文件夹,把MainFormDefine.pas 及 ChildFormDefine.pas 都放进去,这样就不会影响整个目录的结构了。