【问题标题】:Delphi - is it possible to disable Delphi's lazy loading of forms?Delphi - 是否可以禁用 Delphi 的延迟加载表单?
【发布时间】:2016-02-16 08:49:00
【问题描述】:

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

我假设这也适用于使用 Delphi 创建的应用程序,但我在 VCL 源代码中找不到任何关于延迟加载的提及,这表明如果它确实存在,它可能被称为其他东西。

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

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

【问题讨论】:

  • 在发布的链接中更仔细地阅读 Danny Thorpe 的回答。它指的是一个特定的控件 (TPageControl) 和修改的行为。它没有提及 Delphi 应用程序。甚至您(不准确地)引用的部分说的是 TPageControl 而不是 一般的 Delphi 应用程序。 Delphi 应用程序的延迟加载 通常在您需要它们之前不会创建表单(IOW,不要使用自动创建的表单)。您是否有想要解决的特定问题?
  • @Ken Danny 正在谈论 VCL 按需窗口创建。
  • @ross 我不知道按需创建 VCL 窗口是一个问题。你有例子吗?
  • @David:不,Danny 是在谈论按需创建 TPageControl。事实上,他在链接的答案中特别提到了三个不同的时间。他在他的帖子中没有提到 VCL 按需窗口创建。也许您正在阅读与链接的帖子不同的帖子?
  • @Ken 我不认为我正在阅读其他帖子。例如,Danny 说,页面窗口句柄将在首次显示时创建。

标签: delphi vcl tform


【解决方案1】:

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

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

当你运行它时,控制台窗口会显示:

创建的窗口:Button1

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

创建的窗口:Button1 创建的窗口:Button2 创建的窗口: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;

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

创建的窗口:Button1 创建的窗口:Button2 创建的窗口:Button3

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

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

Visible := False;

此外,TTabSheetVisible 属性是这样发布的:

property Visible stored False;

这意味着当一个页面控件开始它的生命时,它的页面是隐藏的,在 VCL 的意义上,Visible 等于 False。正如 Danny 所说,窗口控件是在显示控件时首先创建的。这发生在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 会导致TWinControl.UpdateShowing 执行,并创建窗口句柄。

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

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

【讨论】:

    猜你喜欢
    • 2018-02-15
    • 2013-07-04
    • 2014-07-20
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    • 2016-11-05
    • 2018-08-23
    相关资源
    最近更新 更多