原因是表单在OnCreate
显示之前已创建(因此被触发)。
解决方案 1
一种解决方案是在创建表单时将窗口消息发布到表单。尝试这个:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
const
WM_GREETING = WM_USER + 1;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
protected
procedure WMGreeting(var Message: TMessage); message WM_GREETING;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
PostMessage(Self.Handle, WM_GREETING, 0, 0);
end;
procedure TForm1.WMGreeting(var Message: TMessage);
begin
ShowMessage('Created and shown!');
end;
end.
解决方案 2
另一种解决方案是利用OnActivate
事件,每次表单获得键盘焦点时都会调用该事件:FMessageShown: boolean
向表单类添加一个私有字段。然后,在 中OnActivate
,如果标志为 false(默认情况下是类的字段),则显示您的消息并将标志设置为 true:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
FMessageShown: boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormActivate(Sender: TObject);
begin
if not FMessageShown then
begin
ShowMessage('Created and shown.');
FMessageShown := true;
end;
end;
end.
在实践中,这两种方法都可以完美运行。第一个解决方案的缺点是它可能在某种程度上依赖于“实现细节”,而后一个解决方案的缺点非常明显:每次表单重新获得键盘焦点时,您都会检查一个标志,即使在表单最初创建几周后也是如此,并且该消息已显示。
解决方案 3
一个没有缺点但假设您不需要该OnActivate
事件用于其他目的的解决方案只是在第一次(因此,仅)执行后“取消分配”事件:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormActivate(Sender: TObject);
begin
ShowMessage('Created and shown.');
OnActivate := nil;
end;
end.
(但是,如果您将事件替换为,则这种方法可以扩展到您确实需要事件用于其他目的的情况。)OnActivate := nil
OnActivate := MySecondEventHandler