delphi VCL组件是否有onCreate事件?

des4xlb0  于 2023-01-25  发布在  其他
关注(0)|答案(3)|浏览(171)

程序启动后需要访问一些组件,但我发现从窗体的onCreate事件这样做是不好的,因为此时它们可能仍然不可用(发生访问冲突)。在任何组件中找不到onCreate事件。我错过了什么吗?
这是代码。ValueListEditor的空表单。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.ValEdit;

type
  TForm1 = class(TForm)
    ValueListEditor1: TValueListEditor;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  procedure: Load;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Load;
end;

procedure Load;
begin
    (Application.MainForm.FindComponent('ValueListEditor1') as TValueListEditor)
        .Strings.LoadFromFile('c:\li');
end;

end.
j8ag8udp

j8ag8udp1#

问题不在于你的组件还没有被创建,而在于它已经被创建了,真实的的问题在于当你的主窗体的OnCreate事件被触发时,Application.MainForm属性还没有被赋值,所以你在nil窗体指针上调用FindComponent()
由于Load()仅访问TForm1的成员,因此Load()也应该是TForm1的成员,然后您可以调用它,从而通过隐式Self指针访问您的组件,该指针在窗体的OnCreate事件期间有效,例如:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.ValEdit;

type
  TForm1 = class(TForm)
    ValueListEditor1: TValueListEditor;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure LoadValues;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadValues;
end;

procedure TForm1.LoadValues;
begin
  ValueListEditor1.Strings.LoadFromFile('c:\li');
end;

end.

无论出于何种原因,如果Load()必须是一个独立的过程,那么至少让它使用全局Form1变量,在主窗体的OnCreate事件触发之前,对Application.CreateForm()的调用将分配该变量,例如:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.ValEdit;

type
  TForm1 = class(TForm)
    ValueListEditor1: TValueListEditor;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure LoadValues;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  procedure Load;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadValues;
end;

procedure TForm1.LoadValues;
begin
  ValueListEditor1.Strings.LoadFromFile('c:\li');
end;

procedure Load;
begin
  if Form1 <> nil then
    Form1.LoadValues;
end;

end.

或者,您可以回退到在Screen.Forms[]数组中查找Form1对象,例如:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.ValEdit;

type
  TForm1 = class(TForm)
    ValueListEditor1: TValueListEditor;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
     procedure LoadValues;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  procedure Load;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadValues;
end;

procedure TForm1.LoadValues;
begin
  ValueListEditor1.Strings.LoadFromFile('c:\li');
end;

procedure Load;
var
  I: Integer;
  Frm: TForm;
begin
  for I := 0 to Screen.FormCount-1 do
  begin
    Frm := Screen.Forms[I];
    if Frm is TForm1 then
    begin
      TForm1(Frm).LoadValues;
      Exit;
    end;
  end;
end;

end.
bz4sfanl

bz4sfanl2#

使用窗体的onShow()事件。
但是要注意,onShow()事件在每次显示表单时都会被调用,而不仅仅是第一次。

vohkndzv

vohkndzv3#

在表单中,您应该覆盖DoShow方法并在那里插入代码。由于每次表单从不可见变为可见时都会调用DoShow,因此您还应该在表单中添加布尔变量,并签入DoShow覆盖(如果它是false)。在这种情况下,这是第一次调用DoShow,然后将变量设置为true,并执行第一次需要执行的操作。
请注意,在DoShow中表单是不可见的。如果您需要在表单可见后执行一些操作,您可以从DoShow发布一条自定义消息,并将代码放入相应的消息处理程序中。在执行时,表单才变为可见。

const
    WM_APP_STARTUP         = WM_USER + 1;
type
    TForm1 = class(TForm)
    protected
        FInitialized            : Boolean;
        procedure DoShow; override;
        procedure WMAppStartup(var Msg: TMessage); message WM_APP_STARTUP;
    end;

implementation    
    procedure TForm1.DoShow;
    begin
        // Form is NOT visible but will soon be
        if not FInitialized then begin
            FInitialized := TRUE;
            // Insert your code here
            PostMessage(Handle, WM_APP_STARTUP, 0, 0);
        end;
        inherited DoShow;
    end;
    
    procedure TForm1.WMAppStartup(var Msg: TMessage);
    begin
        // The form is now visible
        // Insert your code here
    end;

相关问题