Delphi7,应用程序窗体出现之前执行Showmessage命令

3
我在想为什么 "showmessage" 命令会在应用程序窗体出现之前被执行,我的意思是,每当我运行该程序时,首先会出现消息,然后才是应用程序窗体:
procedure TForm1.FormCreate(Sender: TObject);
begin
button1.hide;
button2.hide;
image3.picture.loadfromfile('c:\EAS\std.bmp');
showmessage ('Hi');
end;

end.

Delphi首先会显示消息“Hi”。然后它会执行其他操作(如:显示窗体、隐藏按钮、加载图片等)。虽然showmessage是最后一个,但它是最先执行的。我该如何让这条消息在窗体出现、按钮隐藏和图片加载完毕后再出现呢?

谢谢。

1个回答

6
原因是窗体在显示之前就被创建了(因此,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
    { 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,则可以将此方法扩展到需要事件用于其他目的的情况。

1
我宁愿在OnShow事件中向自身发布消息。 - TLama
随意将其包含在您的答案中。这是您从“OnCreate”事件发布该消息的想法。 - TLama
你可以在不使用 OnCreate 的情况下完成这个任务。你需要一个名为 FStartupMessageShown 的布尔类型变量,当你调用 ShowMessage 函数后将其设为 True。或者你可以将 OnActivate 设置为空来实现,也不需要使用布尔类型变量。 - David Heffernan
1
重点是您不需要依赖异步消息分发。目标是在窗口出现在屏幕上时执行某些操作。由于系统会通知您,因此,在我看来,最好响应该通知。 - David Heffernan
1
各位,经过你们漫长的讨论 :P,哪种方法是最好的呢? - user2296565
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接