加载中…
个人资料
步惊云
步惊云
  • 博客等级:
  • 博客积分:0
  • 博客访问:10,636
  • 关注人气:3
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

在Panel中内嵌窗口实现模块化编程

(2020-07-19 11:04:26)
标签:

frame

vcl

delphi

子窗口

分类: VCL

管理型程序往往有很多子模块,如果都写在主程序是非常难于维护的。因此把业务写在子窗口中,然后在主控窗口中创建并调用子窗口,实现模块化编程。以前用delphi xe,只要记住一点,用全局变量引用创建的Form,用后和创建前,一律FreeAndNil,就不会有内存访问错误和重复创建问题,但10.3,这样操作会频繁出现不可解决的内存管理问题,可能是内存管理方式与xe不同导致的,必须另谋出路。

一、用Form还是Frame

必须用Frame。Frame是纯vcl控件,里面的消息管理机制比较简单。Form则是一个复杂的vcl/win32窗口控件,delphi对它进行了复杂处理,比如消除处理机制,同时还有些处理是隐藏的。当然一次性创建相同窗口,一般不会出现问题。但重复创建不同的子窗口,则肯定会频繁出现invalid pointer opertor错误,有时正常有时不正常,这个问题具有一定隐匿性,要反复测试才会重现问题。

二、怎样创建

procedure TYzdjMainFM.RzGroup1Items4Click(Sender: TObject);
var
  FrArchives:TFrArchives;
  OldFr:TComponent;
begin
    FindOldFr(OldFr);
    if Assigned(OldFr) then FreeAndNil(OldFr);
    FrArchives:=TFrArchives.Create(self);
    FrArchives.Name:='FrArchives';
    FrArchives.Parent:=RzPanel2;
    FrArchives.Align:=alclient;
    FrArchives.SetFocus;
    FrArchives.Show;
end;

procedure TYzdjMainFM.RzGroup1Items5Click(Sender: TObject);
  var
   FrFinanReg:TFrFinanReg;
   OldFr:TComponent;
begin
  FindOldFr(OldFr);
  if Assigned(OldFr) then FreeAndNil(OldFr);
  FrFinanReg:=TFrFinanReg.Create(self);
  FrFinanReg.Name:='FrFinanReg';
  FrFinanReg.Parent:=RzPanel2;
  FrFinanReg.Align:=alClient;
  FrFinanReg.SetFocus;
  FrFinanReg.Show;
end;

三、怎样避免内存访问错误

一是必须   FrFinanReg.SetFocus;防止子窗口焦点乱跑,这个是内嵌窗口的通病,

二是创建前必须先在内存里寻找是否有该Frame的实例,如果没有才创建。

这里必须对前面已经创建的各类Frame对象进行销毁。

Procedure TYzdjMainFM.FindOldFr(var OldFr:TComponent);
begin
   if FindComponent('FrArchives')<>nil then OldFr:=FindComponent('FrArchives');
   if FindComponent('FrFinanReg')<>nil then OldFr:=FindComponent('FrFinanReg');

   ..........//所有要创建的窗口对象找到后都必须销毁
end;

三是用局部变量接纳窗口变量,实践表明,如果用全局变量引用不同的窗口变量,又会导致新的内存管理错误。

这样写后,不管子窗口里有任何复杂的内在操作,例如动态创建窗口、流、数据集等,都不会再出现内存访问错误。

四、怎样初始化Frame

 覆盖这两个事件方法,可分别在这两个事件中初始化和事后处理。

 private
    { Private declarations }
  public
    { Public declarations }
     procedure AfterConstruction; override;   //类似OnCreate事件
    procedure BeforeDestruction; override; //类型OnDestroy事件
  end;

但是没有onclose。

//初始化,给DBComboBoxEh1添加下拉选项

procedure TFrArchives.AfterConstruction;
var
  TempFdq:TFdquery;
begin
  inherited;//这个必须写在第一句
  TempFdq:=TFdquery.Create(self);
  TempFdq.Connection:=MainDataMd.FDConnection1;
  TempFdq.Open('select * from dmArchtype order by xh');
  while not TempFdq.Eof do
  begin
    DBComboBoxEh1.Items.Add(TempFdq.Fields[1].asstring);
    TempFdq.Next;
  end;
end;

 



 

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有