刚接触 Delphi 时, 曾以为 Pi 是个常量; 当我知道它是个函数时, 曾被触动.
但 Pi 返回的不过是占 10 个字节的 Extended 类型, 后来竟发现一些对象也这样干, 譬如:
function Clipboard: TClipboard; { Clipbrd } function Printer: TPrinter; { Printers } function Languages: TLanguages; { SysUtils } function RootSprigList: TRootSprigList; { TreeIntf } function ComClassManager: TComClassManager; { ComObj } function ThemeServices: TThemeServices; { Themes } function PropertyCategoryList: TPropertyCategoryList; { PropertyCategories } //这或许已是 Delphi 2010 中类似对象的全部.
特别是其中常用的 Clipboard、Printer、Languages, 无需建立就可以像对象一样使用它们.
这是怎么实现的呢? 查看源码, 它们都有类似的结构脉络(以 Clipboard 对象为例):
interface ... function Clipboard: TClipboard; { 这一般在 interface 的尾部 } ... implementation ... var FClipboard: TClipboard; { 句柄变量 } ... function Clipboard: TClipboard; { 函数实现 } begin if FClipboard = nil then FClipboard := TClipboard.Create; Result := FClipboard; end; ...
当然它们还有个释放的问题, 但我觉得这些对象往往也是它所在的单元也在频繁地使用, 一般到最后释放.
它们巧妙的是:
在我们不使用时, 它们并没有建立;
有使用时立即建立;
再使用时也不会重复建立.
真是非常简单而巧妙的思路!
不能不提另外两个相似的对象:
Application {Forms.TApplication} Screen {Forms.TScreen} //这个两个更常用, 但它们不是函数, 的确是对象变量; 它们是在程序生存期一直存在的.
当一个工程有多个窗体时(恐怕单窗体的程序很少), 那些副窗体能否动态建立呢? 这样做肯定会节约资源、加快启动速度, 我想这无须测试.
上面的做法给了我们很好的借鉴, 不过我想到了两种方法: 1、动态建立; 2、像上面一样通过函数建立.
不管用哪种方法, 都先要禁止程序默认的对窗体的自动建立, 修改如图:

当然也可以直接从工程文件中删除相关的建立代码.
//此时, 我们已经不能使用如下代码打开窗体了: procedure TForm1.Button1Click(Sender: TObject); begin Form2.Show; { 这会出错, 因为此时 Form2 还没有建立 } end; //可以这样: procedure TForm1.Button1Click(Sender: TObject); begin Form2 := TForm2.Create(Application); Form2.Show; end; //但如果想上面这样, Form2 之后又驻留内存了, 怎么释放它呢? 难道要和 Application 一起释放吗? //我们的目的是节约内存, 能不能这样?: procedure TForm1.Button1Click(Sender: TObject); begin Form2 := TForm2.Create(Application); Form2.Show; { 但 Form2.ShowModal; 可以 } Form2.Free; end; //尝试上面的代码, 窗体刚刚显示就被释放了, 此路不通! //还是有解决方案的, 在 Form2 的 OnClose 事件中写点代码: procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; { caNone, caHide, caFree, caMinimize 分别是: 取消、隐藏、释放、最小化 } end; //这样 Form1 中的调用代码也可以简化如下: procedure TForm1.Button1Click(Sender: TObject); begin with TForm2.Create(nil) do Show; end;
这是第一方案, 第二方案准备学习使用前面提到的 Clipboard 等设计手法.
模仿 Clipboard 的实现, 我们可以把 Form2 所在的 Unit2 单元改写为:
unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); end; function Form2: TForm2; implementation {$R *.dfm} var FForm: TForm2; function Form2: TForm2; begin if FForm = nil then FForm := TForm2.Create(Application); Result := FForm; end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; end.
这里的窗体和 Clipboard 还是有区别, 因为我们在用完以后要马上释放, 所以代码可以简化为:
unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); end; function Form2: TForm2; implementation {$R *.dfm} function Form2: TForm2; begin Result := TForm2.Create(nil); end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; end.
这样我们在主窗体又可以这样调用了:
procedure TForm1.Button1Click(Sender: TObject); begin Form2.Show; end; { 这和 Delphi 默认的区别可大了, 这里的 Form2 是个函数; 动态建立、动态释放 }
分类:
从 VCL 中吸取营养
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2009-01-19 Delphi 与 DirectX 之 DelphiX(82): TDIB.DrawMandelbrot();
2009-01-19 Delphi 与 DirectX 之 DelphiX(81): TDIB.ColoredLine();
2009-01-19 Delphi 与 DirectX 之 DelphiX(80): TDIB.BlendPixel();
2009-01-19 Delphi 与 DirectX 之 DelphiX(79): TDIB.LinePolar();
2009-01-19 Delphi 与 DirectX 之 DelphiX(78): TDIB.AntialiasedLine();
2009-01-19 Delphi 与 DirectX 之 DelphiX(77): TDIB.Distort();
2009-01-19 Delphi 与 DirectX 之 DelphiX(76): TDIB.Ink();