【问题标题】:Delphi7, Showmessage command is executed before the application form appearsDelphi7,Showmessage命令在应用程序表单出现之前执行
【发布时间】:2025-12-30 16:15:11
【问题描述】:

我想知道为什么在应用程序表单出现之前执行命令“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 是最后一个,它也会首先执行。如何在表单出现后显示消息,隐藏按钮是否加载图像?

谢谢

【问题讨论】:

    标签: delphi action message


    【解决方案1】:

    原因是在显示之前创建了表单(因此,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,则此方法可以扩展到您确实也需要事件用于其他目的的情况。)

    【讨论】:

    • 我宁愿通过OnShow 事件向自己发布消息。
    • @TLama:但是如果表单被隐藏然后再次显示,该消息将再次出现。但也许您可以在OnCreate 中发布消息。做出回答!
    • 随时将其包含在您的答案中。从OnCreate 事件发布该消息是您的想法。
    • 重点是不需要依赖异步消息派发。目标是当窗口出现在屏幕上时做一些事情。由于系统会通知您,因此在我看来,最好对此做出回应。
    • 那么伙计们,经过长时间的讨论:P,哪一个是最好的方法?