bcb在那里 new出来的控件?

n27741 2007-08-07 04:44:15
我有个疑问

我往form上拖一个button按钮

后 相当于添加了一个button对象

那么 bcb是在那里New出这个对象的呢?

这段代码写在那里了?

最好能给出证明....谢谢 各位大侠
...全文
213 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
n27741 2007-08-08
  • 打赏
  • 举报
回复
明白了 完全明白了 嘎嘎
n27741 2007-08-08
  • 打赏
  • 举报
回复
嗷嗷 收藏!楼上强的
看来搞bcb 不懂pas 是不行的
FFSB 2007-08-08
  • 打赏
  • 举报
回复
ls也太详细了
i_love_pc 2007-08-08
  • 打赏
  • 举报
回复
===============================================================================
⊙ 一个 TForm 对象的创建过程
===============================================================================
下面是一个典型的表单 Form1 的创建过程,缩进代表调用关系(Form1.ReadState 例外,防止缩进太多),带“?”的函数表示我尚未仔细考察的部分,带“*”表示元件编写者需要注意的函数。

Application.CreateForm(TForm1, Form1);
|-Form1.NewInstance;
|-Form1.Create(Application);
|-Form1.CreateNew(Application);
|-InitInheritedComponent(Form1, TForm);
|-InternalReadComponentRes(Form1.ClassName, Form1ResHInst, Form1);
|-TResourceStream.Create(Form1ResHInst, Form1.ClassName, RT_RCDATA);
|-TResourceStream.ReadComponent(Form1);
|-TReader.Create(ResourceStream, 4096);
|-TReader.ReadRootComponent(Form1);
|-TReader.ReadSignature;
*|-TReader.ReadPrefix(Flags, ChildPos);
|-IF Form1 = nil THEN Form1 := FindClass(ReadStr).Create;
|-Include(Form1.FComponentState, csLoading);
|-Include(Form1.FComponentState, csReading);
|-Form1.Name := FindUniqueName(ReadStr);
?|-FFinder := TClassFinder.Create;
*|-Form1.ReadState(Reader);
|-TCustomForm.ReadState(Reader);
{ DisableAlign; }
|-TWinControl.ReadState(Reader);
{ DisableAlign; }
*|-TControl.ReadState(Reader);
{ Include(FControlState, csReadingState); }
{ Parent := TWinControl(Reader.Parent); }
*|-TComponent.ReadState(Reader);
|-Reader.ReadData(Form1);
|-Reader.ReadDataInner(Form1);
|-WHILE NOT EndOfList DO Reader.ReadProperty(Form1);
|-IF PropInfo <> nil THEN ReadPropValue(Form1, PropInfo);
*|-ELSE Form1.DefineProperties(Reader);
|-WHILE NOT EndOfList DO ReadComponent(nil);
|-ReadPrefix(Flags, Position);
|-IF ffInherited THEN FindExistingComponent
|-ELSE CreateComponent;
*|-SubComponent.ReadState(Reader); (Like Form1.ReadState)
?|-DoFixupReferences;

过程简述:

TCustomForm.Create 函数中先调用 CreateNew 设置缺省的表单属性,然后调用Classes.InitInheritedComponent 函数。

InitInheritedComponent 用于初始化一个 root class 对象。该函数的功能就是从应用程序的资源中恢复设计期的表单信息。InitInheritedComponent 的声明如下:

{ Classes.pas }
function InitInheritedComponent(Instance: TComponent;
RootAncestor: TClass): Boolean;

InitInheritedComponent 传入两个参数:Instance 参数代表将要从资源段中恢复信息的对象,RootAncestor 表示该对象的祖先类。如果从资源中恢复信息成功,则返回 True,否则返回 False。InitInheritedComponent 通常只在 root class 的构造函数中调用。

constructor TCustomForm.Create(AOwner: TComponent);
begin
...
CreateNew(AOwner); // 初始化缺省的 Form 属性
Include(FFormState, fsCreating); // 标记为 Creating 状态
if not InitInheritedComponent(Self, TForm) then // 从资源中恢复 Form 信息
raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
...
Exclude(FFormState, fsCreating); // 取消 Creating 状态
end;

InitInheritedComponent 调用自身内置的函数:InitComponent(Instance.ClassType)。InitComponent 先判断 Instance.ClassType 是否是 TComponent 或 RootAncestor,如果是则返回 False 并退出,否则调用 InternalReadComponentRes。

* InitComponent 递归调用自己检查类信息。没看懂为什么要这样设计,如果有谁看懂了请告诉我。

function InitComponent(ClassType: TClass): Boolean;
begin
Result := False;
if (ClassType = TComponent) or (ClassType = RootAncestor) then Exit;
Result := InitComponent(ClassType.ClassParent);
Result := InternalReadComponentRes(ClassType.ClassName,
FindResourceHInstance(FindClassHInstance(ClassType)), Instance) or Result;
end;

InternalReadComponentRes 使用 Instance.ClassName 作为 ResourceName,调用 FindResourceHInstance 找到 class 资源所在模块的 HInst 句柄(因为 class 可能是在动态链接库中),并通过引用方式传递 Instance 对象(* 好像没有必要使用引用方式,InitInheritedComponent 也没有使用引用方式):

{ Classes.pas }
function InternalReadComponentRes(const ResName: string; HInst: THandle;
var Instance: TComponent): Boolean;

InternalReadComponentRes 先检查 class 资源是否存在,如果存在则创建一个 TResourceStream 对象(TResourceStream 的 Create 构造函数把 class 信息的资源内存地址和大小记录在成员字段中),然后使用 TResourceStream.ReadComponent 方法从资源中读取 Instance 的信息。TResourceStream 并没有定义 ReadComponent 方法,而是使用祖先类 TStream 的方法。TStream.ReadComponent 创建一个 TReader 对象,然后使用自己的对象地址(Self)作为参数,调用 TReader.ReadRootComponent 读取 Instance 对象的内容。

{ TReader }
function ReadRootComponent(Root: TComponent): TComponent;

ReadRootComponent 先调用 TReader.ReadSignature。ReadSignature 从 stream 中读取 4 字节的内容,如果读出来的内容不是 'TPF0',则触发异常(SInvalidImage),表示该 stream 的内容是错误的。然后 ReadRootComponent 调用 ReadPrefix 读取元件的状态信息。

如果 Root 参数是 nil,也就是说 Root 对象还没被创建,则直接从流中读取 Root 的类名,再使用 FindClass 函数找到该类在内存中的地址,并调用该类的构造函数创建 Root 的实例。

接下来 ReadRootComponent 调用 Root 的 ReadState 虚函数从流中读取 Root 对象的属性。TComponent.ReadState 只有一行代码:Reader.ReadData(Self);。

ReadData 调用 ReadDataInner 读取 root 元件及 root 的子元件的属性信息。

ReadDataInner 先循环调用 ReadProperty 从流中读取 root 元件的属性,直到遇到 EndOfList 标志(vaNull)。ReadProperty 使用 RTTI 函数,将从流中读出的数据设置为对象的属性。ReadProperty 中还调用了 Instance.DefineProperties,用于实现自定义的属性存储。ReadDataInner 然后循环调用 ReadComponent(nil) 读取子元件的信息。

ReadComponent 的执行过程与 ReadRootComponent 的过程很相似,它根据流中的信息使用 FindComponentClass 找到元件类在内存中的地址,然后调用该元件类的构造函数创建对象,接下来调用新建对象的 ReadState -> TReader.ReadData -> ReadDataInner -> TReader.ReadProperty,重复 ReadRootComponent 的过程。

TReader.ReadComponent 和 TComponent.ReadState 形成递归调用过程,把表单上嵌套的元件创建出来。

最后 InitInheritedComponent 函数返回,一个 root class 对象从资源中实例化的过程完成。
i_love_pc 2007-08-08
  • 打赏
  • 举报
回复
DFM 文件与持续机制(persistent)
http://www.delphibbs.com/keylife/iblog_show.asp?xid=27592
sevencat 2007-08-08
  • 打赏
  • 举报
回复
人家贴得很清楚了,其实这个dfm相当于一个小的脚本或者配置文件,TRead用来根据这个来动态生成窗口的。
你这段代码看不明白的话,基本功可能需要补一补。

Form创建的时候,为什么会调用TRead的方法呢?这个就不明白了 还请FFSB详细说明下
//=====================
你看看main函数有没有一个初始化窗口的函数。Application->CreateForm(__classid(TFrmMain), &FrmMain);我没有仔细看代码,但我认为就是在这个函数里面创建了。
这个dfm,exe是放在资源段的。所以根本没有我们看不见的代码和我们的CPP一起编译。
n27741 2007-08-08
  • 打赏
  • 举报
回复
def文件 那里有???? 我找不到

FFSB TRead这段代码 是Form创建的时候 要用到的吗?

这段代码看不太明白,功能应该是 实例化了 资源中定义的对象

Form创建的时候,为什么会调用TRead的方法呢?这个就不明白了 还请FFSB详细说明下

我猜测 只是猜测

完整的cpp = bcb读dfm后生成的cpp+人写的cpp

也就是说 本质上 拖拽上去的控件 和我们 自己定义 并实例化的控件没区别

只不过bcb另外写了段 我们看不见的代码 且这段代码会合我们的cpp一起编译

只是我们看不到这段代码而已



i_love_pc 2007-08-08
  • 打赏
  • 举报
回复
哦,那楼上讲解一下具体的原理吧
FFSB 2007-08-08
  • 打赏
  • 举报
回复
ls搞笑(编译器?)
i_love_pc 2007-08-08
  • 打赏
  • 举报
回复
.dfm可不是pas代码,
具体的实例化要交给编译器来完成的吧
FFSB 2007-08-08
  • 打赏
  • 举报
回复
function TReader.ReadComponent(Component: TComponent): TComponent;
var
CompClass, CompName: string;
Flags: TFilerFlags;
Position: Integer;
OldParent, OldLookupRoot: TComponent;

function ComponentCreated: Boolean;
begin
Result := not (ffInherited in Flags) and (Component = nil);
end;

function Recover(var Component: TComponent): Boolean;
begin
Result := False;
if not (ExceptObject is Exception) then Exit;
if ComponentCreated then Component.Free;
Component := nil;
SkipComponent(False);
Result := Error(Exception(ExceptObject).Message);
end;

procedure CreateComponent;
var
ComponentClass: TComponentClass;
begin
try
ComponentClass := FindComponentClass(CompClass);
Result := nil;
if Assigned(FOnCreateComponent) then
FOnCreateComponent(Self, ComponentClass, Result);
if Result = nil then
begin
Result := TComponent(ComponentClass.NewInstance); //在这儿 new的
if ffInline in Flags then
begin
Include(Result.FComponentState, csLoading);
Include(Result.FComponentState, csInline);
end;
try
Result.Create(Owner);
except
Result := nil;
raise;
end;
end;
Include(Result.FComponentState, csLoading);
except
if not Recover(Result) then raise;
end;
end;
n27741 2007-08-08
  • 打赏
  • 举报
回复
pas 里面 是这样实例化对象的伐?请赐教
i_love_pc 2007-08-08
  • 打赏
  • 举报
回复
object btn1: TButton //一定要看到new吗?
n27741 2007-08-08
  • 打赏
  • 举报
回复
object Form1: TForm1
Left = 192
Top = 138
Width = 870
Height = 500
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object btn1: TButton
Left = 48
Top = 24
Width = 281
Height = 65
Caption = 'btn1'
TabOrder = 0
end
object btn2: TButton
Left = 48
Top = 96
Width = 137
Height = 97
Caption = 'btn2'
TabOrder = 1
end
object Button1: TButton
Left = 192
Top = 96
Width = 137
Height = 81
Caption = 'btn2'
TabOrder = 2
end
end

这是dfm文件的内容 一个form添加了3个button 貌似只是设置了对象的属性

这个问题确实 也没什么意义 我们完全可以不管那里New出来的 只要能用就行

但是还是打破沙锅问一问...
i_love_pc 2007-08-08
  • 打赏
  • 举报
回复
.dfm文件中
FFSB 2007-08-08
  • 打赏
  • 举报
回复
Application创建Form
Form创建时会加载def中定义的资源
参见/TStream/TWriter/TReader
csrwgs 2007-08-07
  • 打赏
  • 举报
回复
*.def里面有Button的属性定义
而声明是在class的 __published 里面
至于初始化之类的,倒是没有直接写

不然你看看VS2005吧,呵呵
samchoy 2007-08-07
  • 打赏
  • 举报
回复
证明这个有什么用?....谢谢 楼主
MTLee 2007-08-07
  • 打赏
  • 举报
回复
幫樓主頂一把,
我想應該在窗體的創建初始化的時候弄出來的。
歡迎大家拍磚.

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧