我正在尝试将一些组件放在一起,以便在RAD Studio 2009中使用OpenGL。我希望有多个渲染上下文。
我的想法是拥有一个名为GLMaster的“主要OpenGL组件”。它是一个TFrame后代,所以它应该为我提供一个DC。还有一个GLMonitor的组件,充当摄像头。
我在覆盖的GLMaster.Loaded中创建了一个OpenGL RC,如果没有(在ComponentState中的csDesigning),那么“-clause”。我不保留DC,在RAD Studio的帮助中说明你不应该: “TWinControl.Handle 在组件创建或流式传输期间不要引用Handle属性。在第一次引用Handle属性之前,底层窗口不存在。发生这种情况时,会自动调用HandleNeeded方法。“ 我使用GLMaster指向GLMaster.GetCurrentDC(返回HDC)的组件中的函数指针来处理它。
在销毁过程中,GLMonitor希望清理一些渲染到纹理和其他OpenGL资源。检索DC以调用wglMakeActive时,将跟随函数指针并执行跳转到GLMaster.GetCurrentDC。指针(Self)告诉我,在组件流式传输过程中,我们创建了“主RC”,这与GLMaster相同。属性[GLMaster。] Handle现在无效!但是,如果我在应用程序表单的OnClose中释放GLMonitor(仅使用GLMonitor_1.Free;)GLMaster.GetCurrentDC内的句柄是有效的,那么一切正常。
我设法看到GLMaster.Loaded中使用的句柄与完成初始化并向用户显示应用程序表单后的(!?!?)不一样。当我发现这个时,我搜索了我的问题并添加了一个重写的CreateParams来将CS_OWNDC添加到GLMaster组件。那里的一个断点告诉我它正在被执行。
为什么VCL / Delphi会静默地为新创建的组件提供其他句柄,从而间接提供其他DC,即使我提供OWNDC标志?有没有办法得到一个“现在加载所有组件并从.dfm文件读取它们的属性和”-message所以我可以在组件内运行GLMaster.InitEverything?
现在我认为最快的方法是将这个InitEverything放在主窗体的OnShow处理程序中。然后在主窗体的OnClose中调用GLMatser.CleanAll。但我不希望表单中有任何代码,这就是我首先创建组件的原因!
P.S。 并不是说我觉得这个特殊问题很重要,但我使用的是OpenGL 3.2 Core Profile。
答案 0 :(得分:3)
我正在回答“为什么VCL / Delphi默默地为新创建的组件提供其他句柄”。
您的TFrame
(TWinControl
后代)被放置在另一个TWinControl
上,让我们说TForm
。父容器围绕许多设置提供属性包装器,允许我们轻松地进行更改;如果不重新创建windhow句柄,则无法实现其中一些更改。您可以通过在RecreateWnd
,Forms.pas
等中搜索Controls.pas
来获取导致这种情况发生的一长串属性。
调用RecreateWnd
以在运行时实现更改的属性示例:
当您的TFrame
父母需要更改窗口句柄时,您的TFrame
也必须更改窗口句柄。您的Delphi控件,无论是哪个,都需要处理这个,而其他控件最糟糕的是:围绕Windows控件实现包装的控件需要保存状态和重载状态(TEdit,TComboBox,...)
在流式传输(加载表单)时,某些控件会在加载完成之前执行需要窗口句柄的操作。这很可能是你自己的代码!一切都完成加载后,Form可能需要重新创建它的Handle,这反过来会导致你的Frame的句柄被更改。
鉴于VCL的工作方式,您需要为Window Handle做好准备。您应该在Controls.pas
中搜索单词句柄, HDC 。如果您的控件与它的Window Handle和HDC密切相关,那么阅读这些内容符合您的最佳利益。
看看那些例行公事。也许你可以找一个更好的地方来挂钩:
答案 1 :(得分:1)
如果标题是问题,那么不,Delphi在创建框架时不会忽略CS_OWNDC
。刚刚使用以下程序在表单上使用框架进行测试。如果未指定该标志,则会一次又一次地绘制该行,从而产生一条从(0,0)到(10,10)的行。当拥有DC时,该行从(0,0)延伸到(50,50),无需告知,但检索到的DC始终相同。
procedure TFrame2.WmPaint(var Msg: TWMPaint);
var
i: Integer;
DC: HDC;
Pt: TPoint;
begin
inherited;
for i := 1 to 5 do begin
DC := GetDC(Handle);
GetCurrentPositionEx(DC, @Pt);
LineTo(DC, Pt.X + 10, Pt.Y + 10);
ReleaseDC(Handle, DC);
end;
end;
答案 2 :(得分:0)
如果你的问题是:
现在加载所有组件,并从.dfm文件和
中读取其属性答案是:
是,只需覆盖组件的Loaded方法即可。当所有引用都有效时(dfm读取完成后)调用它。