如何在Delphi不同单元复用对象属性并延长其生命周期?
如何在Delphi多个窗体间复用TUser对象并延长其生命周期?
这个问题是Delphi跨窗体共享对象实例的典型场景,核心问题在于你当前的代码里Form1和Form2各自维护了独立的objUser变量:Form2里的objUser没有初始化就调用方法,自然触发访问违例;如果重新Create,那就是一个全新的TUser实例,和Form1里设置了ID的那个完全没关系,所以值会丢失。
下面给你几种实用的解决方案,你可以根据自己的项目场景选择:
方案1:使用全局变量共享实例
最简单的方式是把TUser的实例放在全局作用域里,让所有窗体都能访问到同一个对象。
步骤:
- 在
clsUser_U单元的interface部分添加全局变量:
unit clsUser_U; interface type TUser = class(TObject) // 原有类代码不变 end; var g_GlobalUser: TUser; // 全局变量 implementation // 原有实现代码不变 end.
- 在程序启动时创建这个全局实例,退出时销毁(修改你的项目DPR文件):
program YourProjectName; uses Forms, clsUser_U in 'clsUser_U.pas', Form1_U in 'Form1_U.pas' {Form1}, Form2_U in 'Form2_U.pas' {Form2}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; g_GlobalUser := TUser.Create; // 创建全局实例 try Application.CreateForm(TForm1, Form1); Application.Run; finally g_GlobalUser.Free; // 程序退出时销毁,避免内存泄漏 end; end.
- 修改Form1和Form2的代码,直接使用全局变量:
- Form1的
FormShow方法:
procedure TForm1.FormShow(Sender: TObject); begin g_GlobalUser.setUserID(2); // 直接用全局实例 end;
- Form2的
FormShow方法:
procedure TForm2.FormShow(Sender: TObject); begin lbl1.Caption := IntToStr(g_GlobalUser.getUserID); // 直接读取全局实例的ID end;
优缺点:实现简单,适合小型项目;但全局变量会增加代码耦合度,大型项目里不推荐过度使用。
方案2:通过窗体属性传递实例
如果不想用全局变量,可以在Form2里添加一个公共属性,让Form1在打开Form2时把自己的TUser实例传递过去。
步骤:
- 修改Form2的代码,添加公共属性:
unit Form2_U; interface uses // 原有uses不变 clsUser_U; type TForm2 = class(TForm) lbl1: TLabel; procedure FormShow(Sender: TObject); private objUser : TUser ; public property UserInstance: TUser read objUser write objUser; // 新增公共属性 end; var Form2: TForm2; implementation // 原有实现不变 end.
- 修改Form1打开Form2的代码,传递实例:
procedure TForm1.btnNextFormClick(Sender: TObject); begin Form2.UserInstance := objUser; // 把Form1的objUser传递给Form2 Form2.ShowModal ; end;
- Form2的
FormShow方法保持原有代码即可,现在objUser已经被Form1赋值为正确的实例了。
优缺点:耦合度低,更灵活,适合需要传递不同实例的场景;需要手动管理实例的创建和销毁(比如Form1要负责在合适的时机Free掉objUser)。
方案3:给TUser实现单例模式
如果你的TUser对象在整个程序里只需要一个实例,可以用单例模式,让类自己维护唯一实例,所有窗体都通过统一入口获取这个实例。
步骤:
- 修改TUser类,添加单例逻辑:
unit clsUser_U; interface type TUser = class(TObject) private FUserID : integer ; class var FInstance: TUser; // 静态变量保存唯一实例 constructor Create; reintroduce; // 重新定义构造函数为私有,禁止外部直接Create public class function GetInstance: TUser; static; // 获取实例的入口 class procedure ReleaseInstance; static; // 释放实例 procedure setUserID(iID : integer) ; Function getUserID : Integer ; end; implementation { TUser } constructor TUser.Create; begin inherited; FUserID := 0; // 初始化默认值 end; class function TUser.GetInstance: TUser; begin if FInstance = nil then FInstance := TUser.Create; Result := FInstance; end; class procedure TUser.ReleaseInstance; begin FInstance.Free; FInstance := nil; end; // 原有getUserID和setUserID代码不变 end.
- 修改Form1和Form2的代码,使用单例实例:
- Form1的
FormShow方法:
procedure TForm1.FormShow(Sender: TObject); begin TUser.GetInstance.setUserID(2); // 获取单例实例并设置ID end;
- Form2的
FormShow方法:
procedure TForm2.FormShow(Sender: TObject); begin lbl1.Caption := IntToStr(TUser.GetInstance.getUserID); // 获取单例实例读取ID end;
- 在程序退出时释放单例(修改DPR文件):
program YourProjectName; // 原有uses不变 begin Application.Initialize; Application.MainFormOnTaskbar := True; try Application.CreateForm(TForm1, Form1); Application.Run; finally TUser.ReleaseInstance; // 释放单例实例 end; end.
优缺点:保证全局唯一实例,访问方便;但单例模式会增加类的复杂度,且如果使用不当可能导致内存泄漏或线程安全问题(如果是多线程项目需要额外处理同步)。
内容的提问来源于stack exchange,提问作者Stefan Oberholzer
相关产品推荐
相关产品推荐

