一个关于Frame的问题。(100分)

  • 主题发起人 主题发起人 kenmen
  • 开始时间 开始时间
K

kenmen

Unregistered / Unconfirmed
GUEST, unregistred user!
我有一个程序,除了主程序以外,其它的我都把它设为不能自动运行。
procedure Tclientinfofrm.TFrame11addbtnClick(Sender: TObject);
var
adddialog:Tadddialog;
begin
zldm.clientinfotable.Edit; {zldm是数据模块}
zldm.clientinfotable.Append;
adddialog:=tadddialog.create(self);
adddialog.showmodal;
end;
这样运行它没问题,但关闭adddialog这个窗体时就出错了,显示:
'Access violation at address 0044880d in module '*.exe'.Read of address 000002cc'

adddialog这个窗体的关闭按钮是这样写的:
procedure Tadddialog.Button2Click(Sender: TObject);
begin
zldm.clientinfotable.delete;
adddialog.close;
end;
若是按任务栏上的‘X‘就能正常退出,按这个按钮就出错了。

procedure Tadddialog.FormDestroy(Sender: TObject);
begin
adddialog.free;
end;
这一句我也加了。
不知为啥总是会出这个提示?是与框架有关吗?

还有,TFrame11.Edit1.text:=inttostr(total);这一句若改成:
clientinfofrm.TFrame11.Edit1.text:=inttostr(total);就错了。
TFrame11是clientinfofrm里的一个控件啊。为啥不能这样写?不明?

请指点!
 
zldm是数据模块窗体必须也要自动运行才行
 
对不起,zldm我是把它设为自动启动的。问题依然存在。。。
怎办?
 
请大家踊跃点!!!!
挺急的!!!!!!!!
在此谢过了!!!!
 
cAkk 能帮忙看看吗?
 
不要在类方法中访问类的对象实例!请记住这个原则!
试一试:
procedure Tadddialog.Button2Click(Sender: TObject);
begin
zldm.clientinfotable.delete;
adddialog.close; //改成 Close; 不要访问adddialog实例
end;

procedure Tadddialog.FormDestroy(Sender: TObject);
begin
adddialog.free; //改成 Free; 不要访问adddialog实例
end;

另 clientinfofrm.TFrame11.Edit1.text:=inttostr(total);
应为 clientinfofrm.Frame11.Edit1.text:=inttostr(total);
~~~~~~~
TFrame1是类,而Frame11是TFrame1的实例,看来你还不清楚
类与类实例的区别,这是基础知识啊,看一下OOP的书吧。
 
to:bbkxjy
恕我愚昧,您是说就是在自己的方法里不要调用自己,是吗?
请回答.
 
楼上可能是这个意思,但用self.close却可以!
 
一般是这样,在类的成员方法中不要访问这个类自身的对象,例如,你的 AddDialog 是
TAddDialog 类型的对象,则不要在 TAddDialog 类的成员方法如 TAddDialog.Button2Click
中访问 AddDialog 的属性或方法。因为类的成员方法是该类的所有对象共用的,因此不能
保证 Button2Click 被调用时 AddDialog 已经被创建(实例化)。例如,你另外声明了一个
var
AddDialog2: TAddDialog;
并且这样调用(根据你的程序,TAddDialog 应该是一个 Form,上面放了一个 Button 叫
Button2, Button2 的 OnClick 事件指向 TAddDialog.Button2Click(Sender: TObject)
这个方法):
//创建一个 TAddDialog 对象,即实例化 AddDialog2
AddDialog2 := TAddDialog.Create(Application);
//显示 AddDialog2 窗体
AddDialog2.Show;
...
然后,当你点击 AddDialog2 上的 Button2 时,触发了 Button2 的 OnClick 事件,
即调用 TAddDialog.Button2Click 方法,其中 addDialog.close 这一句将被执行,但
此时 addDialog 这个对象可能还未被实例化(未被创建),它的值还是 nil,这就会引起
地址访问异常。一个办法是确认 AddDialog 已实例化:
if AddDialog <> nil then AddDialog.Close;
但这样被关闭的将是 AddDialog 这个窗体而不是 AddDialog2,而你的原意应该是想关闭
AddDialog2 这个被点击的 Button2 所在的窗体。
类的成员方法实际隐含了一个代表当前类实例的参数 Self,(在 C++ 中则是 this 指针)
procedure Tadddialog.FormDestroy(Sender: TObject);
begin
Free; //等于 Self.Free,Self 可以省略
end;
当调用 AddDialog.FormDestroy 时,进入 TAddDialog.FormDestroy 执行时,Self 就是
AddDialog 实例;而当调用 AddDialog2.FormDestroy 时,进入 TAddDialog.FormDestroy
执行时,Self 就是 AddDialog2 实例。
 
to:bbkxjy
AddDialog2 := TAddDialog.Create(Application);
与AddDialog2 := TAddDialog.Create(self);
有啥不同?
我有时会出现‘stack overflow'这样的提示。
请问为啥?
我可是已释放了的啊。
为啥?
 
to kenmen:
TComponent 的子类都有一个构造方法 Create(Owner: TComponent)。这两句话中的
Application 和 Self,就是这个构造方法中的 Owner 参数的实参啊。这样,AddDialog2
就把自己的 Owner 设为了 Application 或 Self,并把自己加入到 Owner 所维护的
Components 列表中。而一个 TComponent 对象被释放时,会自动把自己维护的 Components
列表中的所有 TComponent 对象都释放掉的。因此,之后如果你没有显式地调用
AddDialog2.Free 来释放 AddDialog2,只要 Application 或这个 Self 被释放,
AddDialog2 也会被释放掉的。当然,若你这样调用 AddDialog2 := TAddDialog2.Create(nil);
那就没有 Owner 会负责释放你的 ADdDialog2 实例了,必须调用 Free 来释放 AddDialog2。
一个例子就是你设计时放在 Form 上的控件,运行时,你释放一个 Form 时,不必逐个释放
它上面包含的控件,因为它们的 Owner 设计时 IDE 已经帮你设好了,一般就是所在的 Form。
你可以看看 On_line help 中关于 TComponent.Create 的帮助。
"StackOver flow" 是栈空间不足,溢出了。一般是你的函数进行了大量递归(直接的或间接的)
的调用,而没有控制好递归结束的条件,或是定义的局部变量占用很大的内存,导致栈空间
耗尽,你可以检查一下。
 
to:bbkxjy
我是写if的嵌套多,有影响吗?
那怎样才能解决?
若TAddDialog这个form是启动时一起启动就不会有问题了,但我把它放到不是自动启动,
要我自己create时,就会出现"StackOver flow" 这个问题了。
请问该怎么解决?
谢了!
 
procedure Tadddialog.FormDestroy(Sender: TObject) 中 adddialog.free 这句你改过
来了吗?是在执行 AddDialog := TAddDialog.Create(self); 这句时产生栈溢出的错吗?
不行就把你 TAddDialog 这个 Form 的启动时可能执行的代码都贴上来吧,如OnCreate,
OnShow,OnActive,OnPaint 等事件的处理过程的代码.
 
我设了两个form,第一个:
var
Form1: TForm1;
i:integer;

implementation

uses Unit3;

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
i:=0;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
form3:Tform3;
begin
i:=i+1;
if i=5 then
begin
hide;
form3:=Tform3.Create(application);
form3.show;
end;
end;

第二个:
procedure TForm3.Button1Click(Sender: TObject);
begin
application.Terminate;
end;

pocedure TForm3.FormDestroy(Sender: TObject);
begin
free;
end;
当按
procedure TForm3.Button1Click(Sender: TObject);
begin
application.Terminate;
end;
这个按钮时,就会说堆栈溢出,程序不能正常退出,为啥?
我只写了这些代码,没其它了,怎么还会这样?

 
我试过若不加
pocedure TForm3.FormDestroy(Sender: TObject);
begin
free;
end;
这句就没问题了,即不free就没问题。
不知为啥?
 
先把那年Form创建后再调用
可以有
Appliction.CreateForm(TForm,FormName);
 
to:lanjiancn
form3:=Tform3.Create(application);
这不已创建了吗?
那Appliction.CreateForm(TForm,FormName);
写在哪?写在form里好像会出错。
 
哎呀!真是晕了头啦。
在 TForm3 的 OnDestroy 中不能调用 Free 方法的。
Free 会调用 Destroy 方法,而在调用 Destroy 之前 BeforeDestruction 方法会自动被
调用,BeforeDestruction 中又调用了 DoDestroy 方法,OnDestroy 中会触发 OnDestroy
事件,这样就间接地造成了你的 TForm3.FormDestroy 方法无穷地递归调用自己,最终导致
栈溢出异常。
你可以在 TForm3 的 OnClose 事件中这样写:
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
...
Action := caFree;
end;
这样关闭 TForm3 类的对象窗体如 Form3 时,Form3 就会将自己 Free 掉的。
或者你可以在适当的时机调用 Form3.Free 释放 Form3 实例。
另外,你是这么写的:
Form3 := TForm3.Create(Application)
将 Application 设为了 Form3 的 Owner,则若没有调用 Form3.Free,程序结束时 Application
对象被释放时自己也会帮你释放 Form3 对象的。
之前光注意到语法,却没考虑到实际的语义了,真对不起!
 
to:bbkxjy
不用对不起,我还要感谢你呢。。。。。
真的感谢你的帮助!!!!!!!!!!
我的方法书上却是这样说的,原来是错的。
真感谢你的帮助。
 
为什么不加一个断点调试一下呢?我已曾遇到过,释放后再调用是不行的,
一加断点就一目了然了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
511
import
I
后退
顶部