原因是窗体在显示之前就被创建了(因此,
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
中,如果标志为假(默认情况下为字段的一个属性),则显示您的消息并将标志设置为真。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormActivate(Sender: TObject);
private
FMessageShown: boolean;
public
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
public
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
,则可以将此方法扩展到需要事件用于其他目的的情况。
OnShow
事件中向自身发布消息。 - TLamaOnCreate
的情况下完成这个任务。你需要一个名为FStartupMessageShown
的布尔类型变量,当你调用ShowMessage
函数后将其设为True
。或者你可以将OnActivate
设置为空来实现,也不需要使用布尔类型变量。 - David Heffernan