{ 控件动态创建的堆与栈 }
1 procedure Form1.TestClick(Sender: TObject); 2 var 3 TestBtn1,BtnTemp:TButton; 4 begin 5 6 {第一步:创建一个Button,令指针TestBtn1指向这个在堆中开辟的内存区。} 7 //////////////////////////////////////////////////////////////////////////// 8 9 {NOTE:必须指定name,后面FindComponent就是通过name来找控件的,TestBtn1不是button的name} 10 TestBtn1:=TButton.Create(panel); //让panel做此button的owner 11 with TestBtn1 do 12 begin 13 Caption:='hello'; //设置Button显示文本 14 name:= 'Button1_test'; 15 left:=16; 16 top:=16; 17 width:=60; 18 parent:=panel; //让panel1做此Button的parent 19 end; 20 21 22 {第二步:制造内存泄漏,同时保存栈中原指针以作补救} 23 //////////////////////////////////////////////////////////////////////////// 24 25 {保存原指针,注意此处控件名区分大小写,请务必和name属性保持完全一致} 26 btnTemp:=TButton(panel.FindComponent('Button1_test')); 27 28 TestBtn1:=TButton.Create(panel); 29 {TestBtn1指向地址更改,从指向caption为hello的caption转为指向caption为Button2的button, 30 第一个button的指针丢失 } 31 with TestBtn1 do 32 begin 33 Caption:='Button2'; 34 left:=16+70; 35 top:=16; 36 width:=60; 37 parent:=panel; 38 end; 39 40 btnTemp.Caption:='world'; 41 BtnTemp.Hint:='这是提示'; 42 FreeAndNil(panel); //虽然发生内存泄漏,owner还是会负责回收,两个button和一个panel都消失 43 ShowMessage('name:'+btnTemp.name); //name被清空 44 ShowMessage(BtnTemp.Hint); 45 try 46 if btnTemp.Caption='world' then //caption 仍为world,很奇怪 47 begin 48 ShowMessage('OK'); 49 btntemp.Caption:='hello world'; //这是非法的,button已经回收了,会造成错误 50 end 51 else 52 begin 53 ShowMessage('crush'); 54 end; 55 except 56 ShowMessage('opps!Invalid pointer.'); 57 end; 58 end;