当前位置:主页>销售管理软件> 列表

一个有趣的问题! 简单? 接受挑战吧! 找记账

销售管理软件版1楼: form1上放有1个listbox,1个memo,2个button,3个edit.
其中edit1,edit2,edit3的text属性分别为Edit1,Edit2,Edit3;
button1的click的代码是:
Edit1:=Edit2; //这就是内存泄漏代码?!
FreeAndNil(Edit1);
(窗体上的其他控件包括窗体不能添加代码)
先执行Button1的click事件.再执行button2的click的代码(要你来编写,要求及功能如下).
问题:
问题1:要你在button2的事件中添加代码,其实现的功能是将窗体上留下的那个edit(除Edit3外)的text属性改为:''又找到你了,呵呵!''
问题2:该遗留下来的Edit(除Edit3外),其name属性是什么,为什么?

2楼: 晕 如管家婆财务软件

3楼: 问题3:如果edit1是动态生成的(不是上面静态生成的):
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1:=TEdit.Create(nil); //不是Edit1:=TEdit.create(self);
edit1.Parent:=self;
edit1.SetBounds(0,0,121,21);
edit1.Text:=''Edit1'';
end;
上面的2个问题又如何?

4楼: Edit1:=Edit2,是将Edit2对象的指针付给了Edit1对象。


如果是将组件对象托放到窗体上,Delphi自动创建该组件对象,用FreeAndNil(Edit1),起不到真正的释放作用。当关闭窗体时,才真正释放了该组件对象。动态生成的Edit1,用FreeAndNil(Edit1)才起作用。所以,并不是内存泄漏。

5楼: to:haiyangmeng
那给出你的button2的click代码,并回答我的问题.

6楼: 第一个问题代码如下
procedure TForm1.Button2Click(Sender: TObject);
Var
i:integer;
begin
for i := 0 to ComponentCount -1 do
Begin
if Components[i] is TEdit then
Begin
if (Components[i] as TEdit).Name <> ''Edit3'' then
Begin
(Components[i] as TEdit).Text := ''又找到你了!'';
showmessage((Components[i] as TEdit).Name);
end;
End;
End;
end;

第二个问题留 下的当然是原来Edit1, 因为执行了
Edit1:=Edit2; FreeAndNil(Edit1);后Edit1这个变量与edit2指向了同一个对象,
FreeAndNil(Edit1)其实是释放了Edit2指向的对象。
所以原来的edit1指向的对象就保留了下来,理所当然它的name是Edit1。
其实name也只是一个对象的属性,它也可以在程序运行中修改它的。

销售管理软件版7楼: to:cangyu


第一个问题Ok!
第二个问题:既然留下的edit的name属性是Edit1,那为什么不可以直接
在button2的click的代码中写上: Edit1.text:=''又找到你了!''进行修改呢?
还有3楼的第三个问题呢?

8楼: 问题4:
针对问题1,既然能找到Edit1,那么在button2的click中进行Edit1的指针修复,使代码最后以 :
Edit1.text:=''还是能找到你!'';
作为结束,修改留下来的Edit(除Edit3外)的text属性.
请你写出Button2.onclick的代码.?

9楼: 晕!

10楼: 当然不行。
我们首先看freeandnil的函数
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;
再看free的函数
destructor TObject.Destroy;
begin
end;

procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;
这下明白了吧。释放的是指针
并且edit1:=edit2把edit1的实例的
指针指向了edit2
所以edit2的实例块和edit1的指针被''free''掉了
但是edit1的实例块还存在。
如果想edit1.text:=''xcjsldjflsjdfsd'';
那么先把edit1的指针找回来


var
i:integer;
begin
for i := 0 to ComponentCount -1 do
Begin
if (Components[i] is TEdit) and (tedit(components[i]).Name=''Edit1'') then
begin
edit1:=Tedit(components[i]);
end;
end;
edit1.text:=''hoho,没藏好,让你看见了.......'';
end;

11楼: to:baiduan
不错!谢谢! 问题1,2,4都被你回答了.
那问题3呢?
上面的方法就不行了!
问题3:如果edit1是动态生成的(不是上面静态方法生成的):
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1:=TEdit.Create(nil); //不是Edit1:=TEdit.create(self);
edit1.Parent:=self;
edit1.SetBounds(0,0,121,21);
edit1.Text:=''Edit1'';
end;
上面的第1,第2个问题又如何?

12楼: 太有意思了。。。[:D]
这个问题。。。。
还没想到。。。。
明天试验一下。[:D] 如财务软件有哪些

13楼: 对于问题1,4我来个最简洁的代码:
procedure TForm1.Button2Click(Sender: TObject);
begin
Edit1:=TEdit(FindComponent(''Edit1''));


Edit1.Text:=''还是能找到你!,呵呵...'';
end;
如果不考虑以Edit1.Text:=''还是能找到你!,呵呵...'';结尾的话,可以直接只一条代码即可:
procedure TForm1.Button2Click(Sender: TObject);
begin
TEdit(Findcomponent(''Edit1'')).Text:=''还是能找到你!,呵呵...'';
end;
问题3谁能解决呢?

销售管理软件版14楼: 问题3的条件执行后(Button1.click触发后):
edit1的实体(会是''尸体''吗???呵呵)对象还留在窗体上,它能随着窗体的移动而移动,它离我们很近,但彷佛又很遥远,
我还能牵着你的手对你说:''还是能找到你!''吗?! :(

15楼: 这肯定是只是一个错误的错误。
vcl不能有这样的错误吧,还是
我理解的问题?
我从create跟踪到Tlist.insert才发现
在vcl的体系中edit1真的被nil掉了。
我真的找不到它。
如果仅仅是在vcl的结构下的话。
我知道windows会对每个分配的
内存块一个索引.
所以我找到了它。
procedure TForm1.Button2Click(Sender: TObject);
function EnumChildWndProc(AhWnd:LongInt;
AlParam:lParam):boolean;stdcall;
var
WndCaption: array[0..254] of Char;
begin
GetWindowText(aHwnd,WndCaption,254);
if wndcaption=''Edit1'' then
begin
showmessage(''我找到你了,你就是''+inttostr(ahwnd));
//这里我不会了。。。。。555555
//虽然我找到了你,但却得不到你。
//难道美丽的东西总是残忍的?

end;
result:=true;
end;
var
i:integer;
hWnd:LongInt;
b:boolean;
begin
EnumChildWindows(self.Handle,@EnumChildWndProc,0);
end;
//如果把所有的都列举出来
//那么会发现有一块内存是没有类型,没有名字的
//其实就是edit2了。
//vcl就是在最后才释放它占用的内存吧。


//在vcl和windows消息的迷宫里我迷失了自己。
//救救一个迷惘的人吧。

16楼: 第三个应该就是内存泄漏了。
创建了一个TEdit对象(A),它的指针保存在Edit1中,但是中途,Edit1指向了Edit2指向的对象(B);
A是存在的,但是我们缺少找到它的途径。
在屏幕上的图像是对象自己画出来的,所以图像也当然还是可以看到了。

17楼: 动态创建的东西在不使用时本身就是释放的。
create了edit后,然后将它的指针指向别的对象实例。那就造成的原先创建它时的实例对象的溢出。
这本身就是写程序时要尽量避免的。还要在窗口关闭时会释放所有这个窗口创建的对象。
而你用Edit1:=TEdit.Create(nil); 建立的,就表明他的所有者不是这个窗口,所以很遗憾ComponentCount不包含它,Findcomponent也找不到它了。那么在窗口关闭时也不会释放它的内存。就真正的造成溢出了。

18楼: 对于第三个问题,使用spy++我们可以捕捉到Edit1''尸体''对象的比较完整的信息:
包括:句柄数,标题,其所属的类,样式,还有它的尺寸信息.
但问题是我们如何才能重新获得对它的控制呢?途径肯定是有,可是路在何方呢?

19楼: 终于找到了,o yeah,o yeah,o yeah,o yeah

procedure TForm1.Button2Click(Sender: TObject);
function EnumChildWndProc(AhWnd:LongInt;
AlParam:lParam):boolean;stdcall;
var
aControl:TWinControl;
WndCaption: array[0..254] of Char;
begin
GetWindowText(aHwnd,WndCaption,254);
if wndcaption=''Edit1'' then
begin
// showmessage(''我找到你了,你就是''+inttostr(ahwnd));
aControl := FindControl(ahwnd);
edit1:=tedit(acontrol);
end;
result:=true;
end;
var
i:integer;
hWnd:LongInt;
ac:TWinControl;
b:boolean;
begin


EnumChildWindows(self.Handle,@EnumChildWndProc,0);
edit1.Text:=''孩子他妈,我找到你了'' ;
end;
//哈哈[:D]

20楼: 嗯,看看“Delphi的内存管理器”delphi源码分析的第七章
http://www.dearbook.com.cn/Book/BookFile/23/TS0023508_Chapter2.pdf

销售管理软件版21楼: 不错,不错!
baiduan辛苦了!!!! [:D]

也谢谢cangyu及其他回贴的朋友!
过两天结帖!

22楼: 我总结一下:
上面在Edit1的指针丢失的情况下,两种找回Edit1指针的方法:
-------------------------------------------
问题1:使用的是Edit1的Owner来找回它指针的.
问题3:使用的是Edit1的parent来找回它指针的.
--------------------------------------------
这两种方法都没有脱离这个小应用程序的范围.
从构造Edit1看:
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1:=TEdit.create(self);<---这个self是问题1找寻的突破口,此时条件就和问题1相同,可如果self变成nil的话,则就只能寻求下面的parent这个突破口了.
edit1.Parent:=self;<-----而这个self是问题3的找寻的突破口
edit1.SetBounds(0,0,121,21);
edit1.Text:=''Edit1'';
end;

可是如果上面两个self都是nil呢?
...别折磨人了吧!打住打住!! 呵呵.....
----------------------------------------------------------------------
使用到的函数有:FindComponent(),Findcontrol(),FindWindowEx()三个函数
----------------------------------------------------------------------
上面的问题1,4简化代码是:
procedure TForm1.Button2Click(Sender: TObject);
begin
Edit1:=TEdit(FindComponent(''Edit1''));
Edit1.Text:=''还是能找到你!,呵呵...'';
end;
或:
procedure TForm1.Button2Click(Sender: TObject);
begin
TEdit(Findcomponent(''Edit1'')).Text:=''还是能找到你!,呵呵...'';
end;
-------------------------------------------------------------
问题3的简化代码是:
procedure TForm1.Button2Click(Sender: TObject);
begin
Edit1:=TEdit(Findcontrol(FindWindowEx(self.Handle,0,''TEdit'',''Edit1'')));
Edit1.Text := ''孩子他妈,我找到你了'';
end;
或:
procedure TForm1.Button2Click(Sender: TObject);
begin
TEdit(Findcontrol(FindWindowEx(self.Handle,0,''TEdit'',''Edit1''))).Text := ''孩子他妈,我找到你了'';


end;
------------------------------------------------------------- 如记账

23楼: 佩服死了,好久没有遇见涵盖
这么多内容的问题了。
有意思极了。
yjingz是个教师吧?
这个问题真能引发人的兴趣。
如果作为教材真的很不错的。
mark下下

24楼: 收藏..

25楼: 我晕!

26楼: 我把1、2都做出来,就是3和4没搞明白,希望多贴出来看看

27楼: to yjingz:
就第三个问题来说,如果创建的是一个Tobject类的对象,还能找到么?
呵呵,楼主试试看。

销售管理软件版28楼: 多人接受答案了。

29楼: 这几天太忙了,没有上来看看,没想到大家讨论得这么多啊。