您的位置:首页 > 编程语言 > Delphi

Delphi 组件开发教程指南(4)组件生成过程(针对TWinControl继承而来的组件)

2010-05-04 17:19 435 查看
还记得在第二章的时候,我用到了procedure CreateParams(var Params:
TCreateParams);这个函数的吧!为什么我会使用这个函数来实现那个对齐的问题呢!现在就来追根底的来看看!这个过程其实是在构建窗口的时候
会调用的,当然我说的这个是针对TWincontrol继承过来的组件说的,从TGraphicontrol等继承过来的是没有这个的。这个函数的产生也
是Windows组件库所特有的,如果列为看官有Windows编程的基础,那么这个就很容易理解了,记得,在Windows编程的时,注册这个窗口类之
前,我们都会为一个窗口类指定一系列的参数,而这个CreateParams函数就是产生在这个注册过程之前,目的是用来为创建过程指定参数。在讲CreateParams的来源之前,我们必须简略说说组件由生成到显示在用户面前的这个过程。这是个灰常纠结的问题,纠结到我不晓得怎么去说(当然
纠结的主要原因还是本人的水平有限,下面大家就简单看看吧,解说可能有错,欢迎指正)。由于组件都是依托于Form之上的,所以组件要显示出来最首要的是
要组件所依托的容器显示出来,那么最首要,我们需要看看Form的创建然后显示出来的过程。至于窗口的创建过程可以参考一下黄叉叉的博客
,在这里我在给他的细化一下,便于我们的工作的展开!这个细化应该是在他那个说明的第5步之前,也就是他说的
此处说明一下:


对 TWinControl 的 Handle 属性的读取会触发 TWinControl

.

GetHandle;
可以察看

Property

Handle; 的声明。


5

、第四步中对 Handle 进行读取,触发下述序列:(TWinControl)
 

Handle->GetHandle->HandleNeeded

这个HandleNeeded是在什么时候第一次调用的,其实他不是在GetHandle的时候第一次调用的,而是在窗口显示出来之前,也就是
Visible变化的过程中第一次调用的,而这个Visible的变化,是在Delphi读取Form资源文件的属性了之后触发(这个属性读取过程,可以
参考Delphi 的持续机制浅探
)。我们看看Visible这个属性变化所触发的过程,这个属性定义在TControl中,属性变化对应的过程为
procedure
TControl.SetVisible(Value: Boolean);beginif
FVisible
<>
Value
thenbeginVisibleChanging;FVisible :
=
Value;Perform(CM_VISIBLECHANGED, Ord(Value),
0
);RequestAlign;end
;end
;
由此可以看到在属性变化的时候发送了一个CM_VISIBLECHANGE的消息出去,然后我们再去这个消息的触发过程
procedure
TWinControl.CMVisibleChanged(
var
Message: TMessage);beginifnot
FVisible
and
(Parent
<>nil
)
then
RemoveFocus(False);ifnot
(csDesigning
in
ComponentState)
or(csNoDesignVisible
in
ControlStyle)
then
UpdateControlState;end
;
本过程在TControl中也有,但是在TWinControl中被重写了,所以我这里只列出了TWinControl的,在Visible变化的时候会
调用UpdateControlState函数来更新控件状态,然后这个更新过程中调用了另外一个更新控件显示的函数UpdateShowing,我们来
看看UpdateShowing这个过程
procedure
TWinControl.UpdateShowing;varShowControl: Boolean;I: Integer;beginShowControl :
=
(FVisible
and
(
not
(csDesigning
in
ComponentState)
ornot
(csDesignerHide
in
ControlState))
or((csDesigning
in
ComponentState)
andnot
(csDesignerHide
in
ControlState))
andnot
(csNoDesignVisible
in
ControlStyle))
andnot
(csReadingState
in
ControlState)
andnot
(csDestroying
in
ComponentState);if
ShowControl
thenbegin
//这个时候如果是第一次显示,FHandle为0,就会调用CreateHandle来创建一个窗口句柄了,也就是说//在这个时候才真真实实的创建Windows的标准控件!if
FHandle
=0then
CreateHandle;if
FWinControls
<>nilthenfor
I :
=0to
FWinControls.Count
-1doTWinControl(FWinControls[I]).UpdateShowing;//之后会更新属于这个控件容器的所有子控件显示end
;if
FHandle
<>0thenif
FShowing
<>
ShowControl
thenbeginFShowing :
=
ShowControl;trySetPerformingShowingChanged(Self);tryPerform(CM_SHOWINGCHANGED,
0
,
0
);finallyClearPerformingShowingChanged(Self);end
;exceptFShowing :
=not
ShowControl;raise
;end
;end
;end
;
CreateHandle过程中调用了CreateWnd,然后CreateWnd得时候就调用我们上面声明的CreateParams来为标准控件传递
参数。上面说了控件的最终容器Form的创建到显示过程,那么我们现在再来说说一般控件的创建显示过程,其实也就和TForm的创建显示过程一样!只是
TForm的显示从读取了属性之后触发,而一般控件由他所在的容器触发,也就是上面的UpdateShowing过程中的实现过程,后面会遍历子控件,然
后更新他们的显示,第一次显示的时候都会触发CreateHandle的过程,所以Windows组件的真实创建过程实际上应该是在组件的第一次显示的过
程中创建,而不是我们调用Create的时候,在Delphi中,我们Create的时候,仅仅是为这个组件提供了一些初始化信息以及各种参数而已。说到
这里,那么,第二章中的CreateParams的实现方法也就相当顺其自然了,因为在CreateParams中为Edit指定其他的扩展样式时,实际
上Windows的真实Edit控件实际上还没有创建出来。那么当指定了新样式,当他创建出来的时候,就自然具备了我们指定的扩展样式了。然后,我在设置
新样式的时候,调用了一个RecreateWnd的方法,这个方法的目的是重建句柄,也就是重建Windows组件,这个函数的实现过程相当简单,仅仅就
是发送了一个组件重建的消息CM_RECREATEWND,然后我们看看这个消息过程的实现方法
procedure
TWinControl.CMRecreateWnd(
var
Message: TMessage);varWasFocused: Boolean;beginWasFocused :
=
Focused;//先保存控件是否是焦点状态UpdateRecreatingFlag(True);//这个函数,我就不贴他的代码了,从他的代码中,我们可以看出来,这个函数//的目的是为所有的子控件打上重建的标记tryDestroyHandle;//释放句柄,同时释放所有子控件的句柄UpdateControlState;//更新控件状态,这个函数上面已经分析,会建立句柄,同时子控件句柄。finallyUpdateRecreatingFlag(False);//重建状态完成end
;if
WasFocused
and
(FHandle
<>0
)
thenWindows.SetFocus(FHandle);//如果重建成功,并且原先有焦点,就恢复原先的焦点状态end
;
可见,这个重建的过程,如果你是一个容器控件,内部有很多子控件的话,使用这个方式来实现某些效果,效率是灰常低下的,所以容器类不建议频繁使用重建方法!至此为止,组件的生成过程就讲解完毕,欢迎专家指正!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: