求教关于在两个窗体中互调的问题(50分)

  • 主题发起人 主题发起人 serial0
  • 开始时间 开始时间
S

serial0

Unregistered / Unconfirmed
GUEST, unregistred user!
开发时,我想从登录窗口进入管理窗口。在管理窗口操作完毕后,也可以重新返回登录窗口。
登录窗口 login.pas TForm2 Form2
管理窗口 admin.pas TForm3 Form3

从登录窗口进入管理窗口的代码是
Form2.Free;
Application.CreateForm(TForm3,Form3);
Form3.show;
这段代码运行正常。
问题出在从管理窗口返回登录窗口上。我的代码是
procedure TForm3.Button1Click(Sender: TObject);
begin
Form3.Free;
Application.CreateForm(TForm2,Form2);
Form2.show;
end;
编译正常。运行时,这三行代码运行也正常。就是当执行完end后,调试器提示出错。
说访问了不能访问的地址。然后又回到程序,只不过,出了一个异常的提示,如下“
Access violation at address 00403586 in module "xxx.exe" Read of adddress FFFFFFD0”
确定后,又可以显示登录窗口了。
如果接着从登录窗口进入管理窗口,那情况就不一定了,有时不出错,有时就出错。
如果重新运行,则有可能第一次登录窗口进入管理窗口时,都出错。

请各位指点如何实现两个窗口之间的相互调用。谢谢。
 
管理窗口为什么要free掉,在其中启动登录窗口就行了嘛。
调用登录窗口代码(可放在管理窗口的formshow事件,还可同时放在菜单等命令中):
Form2:=TForm2.Create(self);
Form2.showmodal;
Form2.free;
登录窗口退出时只要用一个close就可以直接退回到管理窗口。
 
怪了,我的怎么就不出错?
 
to HunterTeam
因为我的程序从登录窗口分别到管理窗口或操作窗口,这两个窗口是由不同的人来操作的。
管理窗口由管理员设置,操作窗口由操作员进行业务应用。管理窗口打开的机会并不多。
所以,我想从管理窗口返回登录窗口后,就没有必要把管理窗口还留在内存中,所以就Free了。

用TForm2.create(self)的做法,我也试过了。
昨天是会提示出错,但还有Form2窗口出来。今天是不提示出错,没有Form2窗口显示。怪了。

还请指点啊。

to 9921023
我是d7企业版、win2k 个人版啊
 
在这个例子里,form3不能由系统自动创建(auto-create),否则出错。查看options
 
to 龙虾:
系统工程中只创建了登录的窗口Form2,并没有创建Form3。Form3是由程序创建的。

我怀疑是Form2释放后,还有什么东西留在内存或保存在程序的什么地方,
所以,再次创建并调用Form2后,导致访问不对的地址。
但是,对于free,以及Delphi7变量窗体等创建释放的更深入的说明,我在书店翻了半天也没有看到。
不知道那位高手能指点一下。
 
form2不释放,隐藏就可以了。
还有你用destory试试(释放窗口)
 
to 陈晨
destroy的办法,我也试过了。一样会出错。
 
Form2.free释放掉Form2所占用的内存,但是form2的应用却没有为NIL,
..
form2.free;
form2 := nil;
或者
FreeAndNil(form2);
你TRY 下看看?
 
每次打开窗口时:
Form2:=TForm2.Create(self);
Form2.showmodal;
Form2.free;
From2:=nil;
关闭窗口时:
From2.close;
 
to bjackal、bbs-wqt 还是不行。
我发现:
如果从form3返回form2时,如果我不把form3free掉,那不会出现错误。
但是,问题是我的设计中,从form3返回时,是要把form3给彻底删除掉,所以也不能用隐藏。
这路不通啊。

如果,我form3.free,程序能进行,但执行接下来的end时,就弹出访问异常地址了。
我怀疑是form3给free后,form3在内存中消失,这个过程本身也被清掉了,所以会访问一个异常地址。
但是,如果按这样的解释,从form2进入form3时,我也把form2给free了,程序却可以正常运行,
可见我上面的想法是不对的。

各位能否就这个问题,指点一下啊。
 
你这种方法当然很容易出错,而且,你的方法与面向对象的设计原则相悖了。
推荐你一个处理的方法:
main.pas
在procedure AdminButtonClick(Sender:TObject);代码:
if ExecuteLoginDlg() then
ExecuteAdmin();

在procedure OperatorButtonClick(Sender:TObject);代码:
if ExecuteLoginDlg() then
ExecuteOperation();

Login.pas
//var From2:Tform2 //可以注释掉,增加一个全局函数
function ExecuteLoginDlg:Boolean;
begin
with TForm2.Create(Application) do
try
Result:=ShowModal=mrOk; //注意,要在点击确定登陆成功的处理事件中,设置form的ModalResult=mrOk,则函数可以得到正确的返回结果
finally
free
end;
end;
同样的道理
在Admin窗口和Operator窗口,声明类似的全局过程或函数,
在main窗口直接调用这些函数来执行相关任务。
其实,系统在处理窗口的创建和释放是很快的,没有必要一定要保留类似Login这一类的窗口;
用完就释放,可以减少资源的占用,也可以很好的保护你的内存资源不出问题。
你所遇到的问题实际上就是声明了变量,free了,但又没有设置变量指针为nil,导致再次进入时,就进入了空指针,
总之,你现在的使用方法很不安全。
参看一下delphi下的Demo/Db/MastApp/ 这个例子吧
有问题,可以再联系:hding99@sina.com
 
你在关闭前都用了free,可之后怎么又要它显示,如果显示前重新创建它当然不会出错了。
我想登录窗体就不要free掉,它占不了多大的资源。
 
to hding:
你说的很对啊。我想我这样处理,的确是不太好。
我的做法是把form2(3)的事件中,把form2(3)自己给free了。
可是,事件本身还没有结束,当它到达end时,原来的内存已经没有了,
从而导致访问不正常地址,从而引发异常。

不过,我从delphi的帮助中找到了另一个方法release。
这个方法处理时会等到form中所有事件都处理完了,才会彻底地删除本身。
文档中建议用它来取代free方法。

Release method (TCustomForm)
Destroys the form and frees its associated memory.

Delphi syntax:

procedure Release;

C++ syntax:

void __fastcall Release(void);

Description

Use Release to destroy the form and free its associated memory.

Release does not destroy the form until all event handlers of the form and event handlers of components on the form have finished executing. Release also guarantees that all messages in the form's event queue are processed before the form is released. Any event handlers for the form or its children should use Release instead of Free (Delphi) or delete (C++). Failing to do so can cause a memory access error.

Note: Release returns immediately to the caller. It does not wait for the form to be freed before returning.

非常感谢各位的大力帮忙。分数太少,各位多多包涵。
 
后退
顶部