Delphi - 是否可以禁用Delphi的延迟加载表单?

时间:2015-11-15 01:14:45

标签: delphi vcl tform

我听说Delphi应用程序使用“延迟加载”,推迟加载表单组件,直到实际引用它们为止。在another post中提到 - “这就是我们将TPageControl更改为延迟加载的原因 - Delphi IDE的选项对话框加载时间太长了!”

我认为这也适用于使用Delphi创建的应用程序,但我在VCL源代码中找不到任何延迟加载的提及,这表明如果确实存在,可能会将其称为其他内容。

在正常使用情况下,应用程序不经常启动并运行很长时间,可能需要放弃更快的启动时间,并在第一次实际使用时更快地绘制VCL组件。

Delphi程序员对此有何控制权? (LazyLoad := false ;没有用;-)

1 个答案:

答案 0 :(得分:5)

考虑以下简单的演示项目:

<强> Project1.dpr

program Project1;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

<强> Unit1.pas

unit Unit1;

interface

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

type
  TButton = class(Vcl.StdCtrls.TButton)
  protected
    procedure CreateWnd; override;
  end;

  TForm1 = class(TForm)
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    TabSheet3: TTabSheet;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TButton.CreateWnd;
begin
  inherited;
  Writeln('Window created: ' + Name);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  AllocConsole;
end;

end.

<强> Unit1.dfm

object Form1: TForm1
  Caption = 'Form1'
  ClientHeight = 299
  ClientWidth = 635
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object PageControl1: TPageControl
    Left = 40
    Top = 40
    Width = 537
    Height = 233
    ActivePage = TabSheet1
    object TabSheet1: TTabSheet
      Caption = 'TabSheet1'
      object Button1: TButton
        Caption = 'Button1'
      end
    end
    object TabSheet2: TTabSheet
      Caption = 'TabSheet2'
      object Button2: TButton
        Caption = 'Button2'
      end
    end
    object TabSheet3: TTabSheet
      Caption = 'TabSheet3'
      object Button3: TButton
        Caption = 'Button3'
      end
    end
  end
end

运行时,控制台窗口显示:

Window created: Button1

当你依次选择每个页面时,会创建其他按钮,如控制台窗口所示:

Window created: Button1
Window created: Button2
Window created: Button3

现在更改OnCreate事件处理程序以强制在创建表单时显示每个页面:

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  AllocConsole;

  for i := 0 to PageControl1.PageCount-1 do begin
    PageControl1.Pages[i].Visible := True;
  end;
end;

现在首次显示表单时,控制台窗口显示为:

Window created: Button1
Window created: Button2
Window created: Button3

这是因为,正如Danny所说,窗口在显示之前不会被创建。

现在,关于页面控件的细微差别在于处理页面的可见性。 TTabSheet的构造函数包含:

Visible := False;

此外,Visible的{​​{1}}属性发布如下:

TTabSheet

这意味着当页面控件开始生命时,其页面将被隐藏,在VCL意义上property Visible stored False; 等于Visible。正如Danny所说,当控件显示时,首先会创建窗口控件。这发生在False内部,如下所示:

TWinControl.UpdateShowing

页面开始没有显示,然后当它们在procedure TWinControl.UpdateShowing; var ShowControl: Boolean; I: Integer; begin ShowControl := (FVisible and (not (csDesigning in ComponentState) or not (csDesignerHide in ControlState)) or ((csDesigning in ComponentState) and not (csDesignerHide in ControlState)) and not (csNoDesignVisible in ControlStyle)) and not (csReadingState in ControlState) and not (csDestroying in ComponentState); if ShowControl then begin if WindowHandle = 0 then CreateHandle; // <-- this is the key if FWinControls <> nil then for I := 0 to FWinControls.Count - 1 do TWinControl(FWinControls[I]).UpdateShowing; end; .... end; 中变为活动时,将对新活动的页面执行以下操作:

TPageControl.ChangeActivePage

Page.BringToFront; Page.Visible := True; 设置为Visible会导致True执行,并且正在创建窗口句柄。

这就是为什么在表单创建时使所有页面可见的上述技巧会产生你想要的效果。

现在,以上所有内容都是以页面控制为中心的。对于许多其他控件,如果控件可见,则在创建表单时首先创建窗口。如果您遇到特定表格的特定问题,那么最好分享具体细节。