为什么我的 TFrame 没有“看到”已发布的消息?
我最近刚刚开始大量使用 TFrame(好吧,是的,我一直生活在岩石下......)。我认为框架支持消息处理方法声明——而且我见过很多这样的例子。那么为什么这个简单的 TFrame 测试单元永远看不到它发送给自身的消息呢? (当我发现在我的大型应用程序中没有调用消息处理程序时,我创建了测试。)
unit JunkFrame;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
const
DO_FORM_INITS = WM_USER + 99;
type
TFrame1 = class(TFrame)
Panel1: TPanel;
private
procedure DoFormInits(var Msg: TMessage); message DO_FORM_INITS;
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{$R *.dfm}
constructor TFrame1.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
PostMessage(self.Handle, DO_FORM_INITS, 0, 0);
end;
procedure TFrame1.DoFormInits(var Msg: TMessage);
begin
ShowMessage('In DoFormInits!');
end;
end.
该框架仅包含一个 TPanel,并且该框架用于一个简单的主窗体,该主窗体仅包含该框架和一个关闭按钮。
我缺少什么?
I just recently begun using TFrames heavily (OK, yes, I've been living under a rock...). I thought frames supported Message hander method declaration--and I've seen many examples of that. So why does this simple test unit for a TFrame never see the message it posts to itself? (I created the test when I figured out that message handlers weren't being called in my larger application.)
unit JunkFrame;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
const
DO_FORM_INITS = WM_USER + 99;
type
TFrame1 = class(TFrame)
Panel1: TPanel;
private
procedure DoFormInits(var Msg: TMessage); message DO_FORM_INITS;
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{$R *.dfm}
constructor TFrame1.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
PostMessage(self.Handle, DO_FORM_INITS, 0, 0);
end;
procedure TFrame1.DoFormInits(var Msg: TMessage);
begin
ShowMessage('In DoFormInits!');
end;
end.
This frame only contains a TPanel, and the frame is used on a simple mainform which contains only the frame and a Close button.
What am I missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我看到两种可能性:
您的程序尚未开始处理消息。仅当您的程序调用
GetMessage
或PeekMessage
,然后调用DispatchMessage
时,才会处理已发布的消息。这发生在Application.Run
内部,因此如果您的程序尚未到达那里,那么它不会处理任何已发布的消息。您的框架的窗口句柄已被销毁并重新创建。访问 Handle 属性会强制创建框架的窗口句柄,但如果框架的父级尚未完全稳定,则它可能会销毁自己的窗口句柄并重新创建它。这会强制它的所有子级执行相同的操作,因此当您的程序开始处理消息时,您发布消息的句柄并不存在。
要解决第一个问题,只需等待。您的程序最终将开始处理消息。要解决第二个问题,请重写框架的
CreateWnd
方法并在其中发布消息。该方法在创建窗口句柄后被调用,因此您可以避免强制过早创建句柄。不过,句柄仍然有可能被销毁并重新创建,每次发生这种情况时都会调用CreateWnd
,因此您需要小心,因为您的初始化消息可能会多次发布(但绝不会多次发布到同一窗口句柄)。这是否正确取决于您需要执行哪种初始化。I see two possibilities:
Your program hasn't started processing messages yet. Posted messages are only processed when your program calls
GetMessage
orPeekMessage
and thenDispatchMessage
. That occurs insideApplication.Run
, so if your program hasn't gotten there yet, then it won't process any posted messages.Your frame's window handle has been destroyed and re-created. Accessing the
Handle
property forces the frame's window handle to be created, but if the frame's parent hasn't quite stabilized yet, then it might destroy its own window handle and re-create it. That forces all its children to do the same, so the handle you posted the message to doesn't exist by the time your program starts processing messages.To fix the first problem, just wait. Your program will start processing messages eventually. To fix the second problem, override your frame's
CreateWnd
method and post the message there. That method gets called after the window handle has been created, so you avoid forcing the handle to be created prematurely. It's still possible for the handle to be destroyed and re-created, though, andCreateWnd
will be called each time that happens, so you'll need to be careful since your initialization message might be posted more than once (but never to the same window handle multiple times). Whether that's correct depends on what kind of initialzation you need to do.我能想到的唯一解释是,在发布消息之后和泵送消息队列之前,会重新创建框架的句柄。尝试在 OnShow 中发帖。
The only explanation for this that I can come up with is that your frame's handle is recreated after you post the message and before the message queue is pumped. Try posting in an OnShow.