问题提出:
从MainForm动态创建一个Form(已经设计好的),代码为:
if (NOT Assigned(ActiveForm)) then
ActiveForm:= TActiveForm.Create(Application);
if(Assigned(ActiveForm)) then
ActiveForm.Show()
当调试运行后从ActiveForm的FormCreate()事件中直接使用Self.Close()关闭ActiveForm后,再次执行上述创建窗体的代码后发生错误,并强制关闭。解决方法:
在ActiveForm的FormCreate()事件中使用PostMessage来关闭窗体。代码:
Windows.PostMessage(Self.Handle, WM_CLOSE, 0, 0);问题:
虽然关闭窗体的问题已经解决了,但是其中一些具体细节还不知道。为什么Self.Close()会发生错误,而PostMessage()却可以正常执行?
为什么是第二次时发生错误而不是第一次时???
FormCreate()事件中一般会有一些初始化的代码,并且一个Form一般都会有一些组件,当从FormCreate()中直接关闭时,是不是因为某些组件未能正常初始化或释放而发生错误?如果这样理解的话,PostMessage()是不是提供了一个缓冲时间,来完成FormCreate()事件后再关闭Form?
从MainForm动态创建一个Form(已经设计好的),代码为:
if (NOT Assigned(ActiveForm)) then
ActiveForm:= TActiveForm.Create(Application);
if(Assigned(ActiveForm)) then
ActiveForm.Show()
当调试运行后从ActiveForm的FormCreate()事件中直接使用Self.Close()关闭ActiveForm后,再次执行上述创建窗体的代码后发生错误,并强制关闭。解决方法:
在ActiveForm的FormCreate()事件中使用PostMessage来关闭窗体。代码:
Windows.PostMessage(Self.Handle, WM_CLOSE, 0, 0);问题:
虽然关闭窗体的问题已经解决了,但是其中一些具体细节还不知道。为什么Self.Close()会发生错误,而PostMessage()却可以正常执行?
为什么是第二次时发生错误而不是第一次时???
FormCreate()事件中一般会有一些初始化的代码,并且一个Form一般都会有一些组件,当从FormCreate()中直接关闭时,是不是因为某些组件未能正常初始化或释放而发生错误?如果这样理解的话,PostMessage()是不是提供了一个缓冲时间,来完成FormCreate()事件后再关闭Form?
解决方案 »
- 请教大家,动态创建的窗口怎么最大化
- 请问怎么获取硬盘转速
- delphi编写的dll函数,delphi调用没问题,vb调用有问题请关注一下,另有一贴也有分
- 加急,小妹求助电子白板程序一个,望高手大虾帮忙!!!
- 告诉我,一个新手,
- 二进制文件问题,很简单的
- 碰到个大问题,求助啊
- 大家好,我是新人,刚接触delphi,现有一关于delphi internet控件问题请教各位老鸟们
- 十在不好意思,不知如何在delphi中计算乘幂,只好请教大家,请告知具体用法,好像EXP也用不起,不知我的格式写错没有?
- 如何动态讲网络运行情况简单显示在一个节点分布图上
- 关于注册表REG_MULTI_SZ类型值的读取。。急
- 数据集TClientDataset保存数据时报错,是什么原因!
我是个懒人,如果遇到困难的问题,特别是涉及代码的,一般解决流程是:1>到CSDN社区提问;2>刷新帖子看回复;3.1>运气好,有高手给了解决方法,解决;3.2>运气差,再发帖子如果运气十分以及相当并且非常差,直接导致死循环最后被迫自己解决问题调查内容就是:
看这个帖子的人有多少是和我一样或相仿的???如果都是的话,那么,证明CSDN和中国的短信业务一样,都是垃圾的东西比较多,当然也不排除垃圾堆里有好东西最后向CSDN给我提供的帮助致谢,我给CSDN导致的麻烦致歉!
动态创建已经设计好的窗体,从动态窗体中的FormCreate()时间中使用Self.Close()关闭自己。然后再次创建如此而已。
一直在线等,一直没有等到好答案,所以看了看VCL。窗体的部分看过了,了解了不少,但是看完后有更多不明白的了,不过感觉还算不错。
不过Windows消息部分一直没看,所以你的回答很有帮助。不过细节还是少了点。等等看还有没有更好的答案,再结贴。
先不要尝试使用API或者直接使用Message。
考虑这样一段代码:
type
TFoo = class;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
Foo: TFoo;
{ Private declarations }
public
{ Public declarations }
end;
TFoo = class(TObject)
private
FForm:TForm;
function GetForm: TForm;
public end;
var
Form1: TForm1;implementation{$R *.dfm}function TFoo.GetForm: TForm;
var S:String;
begin
if Assigned(FForm) then
Result := FForm
else
begin
FForm:=TForm.Create(nil);
Result:=FForm;
end;
end;procedure TForm1.Button1Click(Sender: TObject);
var AForm:TForm;
begin
AForm:=Foo.GetForm;
AForm.ShowModal;
FreeAndNil(AForm);
end;procedure TForm1.FormCreate(Sender: TObject);
begin
Foo:=TFoo.Create;
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
Foo.free;
end;
当第一次按Button1时,正常。第二次的时候,会发生什么事呢?
难道用var声明类的一个对象后就已经分配了vmt空间,而不是在create时分配的?
所以,Delphi中,有一组相关的事件通知这类事情,你可以查一下帮助,这类事件是
procedure FreeNotification(AComponent: TComponent);
procedure Notification(AComponent: TComponent; Operation: TOperation);
procedure FreeNotification(AComponent: TComponent);
FormCreate与FormDestroy;现在,我干脆贴出form文本出来。
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TFoo = class;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
Foo: TFoo;
{ Private declarations }
public
{ Public declarations }
end;
TFoo = class(TComponent)
private
FForm:TForm;
function GetForm: TForm;
public
procedure Notification(AComponent: TComponent; Operation: TOperation); override; end;
var
Form1: TForm1;implementation{$R *.dfm}function TFoo.GetForm: TForm;
var S:String;
begin
if Assigned(FForm) then
Result := FForm
else
begin
FForm:=TForm.Create(nil);
Result:=FForm;
FForm.FreeNotification(Self);
end;
end;procedure TFoo.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if(AComponent=FForm)and( Operation = opRemove) then
begin FForm:=nil
end;
end;procedure TForm1.Button1Click(Sender: TObject);
var AForm:TForm;
begin
AForm:=Foo.GetForm;
AForm.ShowModal;
FreeAndNil(AForm);
end;procedure TForm1.FormCreate(Sender: TObject);
begin
Foo:=TFoo.Create(Self);
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
Foo.free;
end;
end.///以下是FORM
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 327
ClientWidth = 436
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 192
Top = 80
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
end
在Delphi工程中,工程文件中,一般会自动创建Form,在Option中可以移除。
上面的代码中,创建是由单元程序自主控制的。自主控制的Form显然要令人放心得多。
解决办法就是在窗口onClose的时候Action 等于 caFree(详细可以看delphi帮注有例子)
而且我不理解为什么楼主会在OnCreate里面调用Close方法。
如果你不想让它出现可以在OnShow的时候Close掉,这样绝对不会有问题的
虽然你这么写,第一次没有出错,不过不能证明你这样就对...
再回过头来看TFoo,再思考一个问题:如果外部调用者并没有Free Form,那么,这个Form会被Free掉吗?
答案是不会的。为什么???delphi的工程文件中也自动创建也自动销毁呀?!!
此时,要特别注意这样一个方法。
function TFoo.GetForm: TForm;
var S:String;
begin
if Assigned(FForm) then
Result := FForm
else
begin
FForm:=TForm.Create(nil);//再看一看!!!
Result:=FForm;
FForm.FreeNotification(Self);
end;
end;关键行是 FForm:=TForm.Create(nil);
也就是说,Owner为nil。
在Form(所有控件)的基类 TComponent中,有一个子控件列表,它自维护这个列表,如果destroy时,这个列表中有控件不为nil,那么,它会自动Free掉它们,相当于说,TComponent被分到的饭它会全部消化掉。
观察.dpr工程文件中, 其实上,自动创建的Form,DataModule的Owner全都是Application,所以能够被自动释放。
这就是我们创建控件时为什么都会象下面这样用的原因。
AComponent := TComponent.Create(Self);
ALabel:=TLabel.Create(Self);
...
AEdit:=TEdit.Create(Self);
...这样可以简化代码,反正我交给self了,self会消化掉的,我只关心我要的业务逻辑控件就行了。其他的,管太多,我累不累呀我?!
TForm有着一些特别的特点,在Close的时候,可以指定是不是释放。closeAction = caFree,就会自释放。通常,Close只不过是隐藏Form罢了,如果你指定了caFree,则它会自释放。 再回过头来,看看TFoo。
FForm那碗饭并没有分给任何人,如果大家都放任不管,它一定会放在那里变馊。 所以,我们要完善一下TFoo类,需要重写Destroy方法。TFoo=class(TComponent);
....
...
public
...
destructor Destroy;override;
end;
...destructor TFoo.Destroy;
begin
if FForm<>nil then
begin
FreeAndNil(FForm);
end;
Inherited Destroy;
end;真是因为有了FreeNotification,我们也重写了Notification,所以可以很放心地检查FForm是不是nil(当然,也可以用Assigned(FForm)),也可以保证正确释放对象。对象,创建,销毁,通知,宿主,这些内容不搞清楚,不容易抓住程序中的错误。
在那个方法中释放。
这是因为,OnCreate事件发生时,Form的constructor 方法CreateNew ,并没有真正的执行完毕,结果被释放了,虽然这样并不一定会导致错误(视代码而定),但并不安全。
关于你的Post message不会出错,可能的原因比较多,要具体分析:
先说Free的问题,我们先不管是不是在OnCreate中Close,只管Close本身。
在TActiveForm 的OnClose中,如果CloseAction设成了caFree,那么出错的原因与我们所讨论的TFoo对象是一样的。
如果不是,那么情况就比较复杂了。应该是因为在OnCreate中执行Close的原因:
PostMessage的特性是发送消息到消息对列,然后程序并不停止,立刻往下执行这个过程是十分快的。而Close是会完全执行的,不执行完是不会继续下去的。正是因为你在OnCreate中调用Close,然后又自动Free。类并没有完全被完整创建。因为没有详细的代码,出错的原因不可预计。因为在Create过程中,会读取DFM中的控件,会调用MakeObjectInstance,然后,响应一系列的消息,包括CreateParam,CreateWnd,很多。有不可知且不可控制的原因会令到响应到WM_Close的时候并不释放自身或者并不会引起冲突。这样的代码实在实在是不安全。不知道什么时候在什么机器上就会出错。建议:改变设计。
请说明为什么要在OnCreate中Close? 为什么不能Hide?
请说明是否为MDIChild。
请说明主要意图,OnCreate中Close,令人感到相当奇怪。打个比方吧,就象生孩子,才出来一半,你又给塞回去,我的天。且不说小孩子(TActiveForm),就是妈妈(TApplication)也受不了的吧??
哈哈!!!你真地很幽默。你要是当老师,学生一定爱听课,上课肯定不会睡觉的。真地非常非常感谢!!!
篇幅太大了。估计用了很长时间来打字吧?再次致谢
还有:
xjjrocker(了无痕)
heluqing(鉴之小河〖挣大钱娶美女〗)(越来越硬)
谢谢了先说说和题目不相关的事情,我的ADSL猫坏掉了。因为这几天打雷下雨太厉害无奈。铁通的网络,03年开始用的。那个时候是买的猫,¥400.00的设备费,就是猫费!晕死。更可气的是,现在他们居然说可以租用而不用买了。区别就是:买的坏了自己弄,租用的坏了他们负责弄!亏死我了。今天刚刚借了个猫,凑合着用先
不过对于我自己来说看的已经够多了。回答:
1> 请说明为什么要在OnCreate中Close? 为什么不能Hide?
首先是习惯问题。对象不用了就要销毁。节约
然后,涉及到我写的代码,窗体是一个关于设置/配置的窗体。在OnCreate中会调用函数读取ini文件并将数据保存到窗体中的一些变量中,如果出错(文件不存在,内容不符合等等),再保留窗体就没有意义了,当然就要Close掉了。不过,就像你(teapot(茶壶))说的一样,Close的地方有问题。不过用PostMessage就可以了,当窗体Create完成后,PostMessage会将他销毁调,因为Form存在且有效,Form中的控件、组件等等什么的也都创建并初始化完毕,也都存在且有效。所以用PostMessage代替Close,代码本身没问题。不过就是用了非Delphi的罢了,看着不爽——视觉方面的问题,不过能用就好。2>请说明是否为MDIChild。
否。标准的MDI不是很好用,不是说有错误或BUG,而是说功能不强。为此,专门作了类似于TAppBuilder(Delphi主窗体)的主窗体,完成了90%多了。基本功能都实现了。为此也学习了一些API以及Windows消息,感觉虽然累了点,不过还好总算作出来了——打个比方吧:就像生孩子,生出来了,不过还没听到哭声