stepand76
stepand76

Reputation: 475

Delphi: Hiding/showing TWinControl objects in a form is pretty slow. How to get it faster?

I have simple VCL form application in Delphi XE5. In the main form there are hudreds of TEdit components. Now I realized that setting visibility of all these edits is pretty slow. It takes ca 1 second on my computer while they are hidden/shown.

Please note that this is sample intended only for demostrate the issue. I know that this can be solved by inserting edits to a panel and hiding/showing the panel. But this is not possible in our application where edits are inserted to a form by an end user. Also we don't know which edits visibility will be controlled.

How to get it faster?

Note that when I use TLabel (TGraphicControl) instead of TEdit (TWinControl) then it is fast!

procedure TForm1.CheckBox1Click(Sender: TObject);
var
  C: TControl;
  i: Integer;
begin
  for i := 0 to ControlCount - 1 do
  begin
    C := Controls[i];
    if C.ClassName <> 'TCheckBox' then
      C.Visible := CheckBox1.Checked;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  C: TEdit;
  i: Integer;
  j: Integer;
begin
  for i := 0 to 60 do
    for j := 0 to 20 do
    begin
      C := TEdit.Create(Self);
      C.Width := 40;
      C.Left := 20 + 50 * j;
      C.Top := 50 + 25 * i;
      C.Parent := Self;
    end;
end;

Upvotes: 2

Views: 1815

Answers (1)

David Heffernan
David Heffernan

Reputation: 613441

Your controls are parented directly by the form. Instead create a panel with alClient align and set the panel's Parent to be the form.

When you create the edit controls, make their Parent be the panel. When you wish to hide the edit controls, hide the panel.

If you don't want to, or cannot, make such a drastic change, then you can batch the changes with BeginDeferWindowPos, DeferWindowPos and EndDeferWindowPos. You might have code along these lines:

const
  Flags = SWP_NOZORDER or SWP_NOOWNERZORDER or SWP_NOACTIVATE or SWP_NOSIZE or 
    SWP_NOMOVE or SWP_HIDEWINDOW;
var
  i: Integer;
  wpi: HDWP;
  wnd: HWND;
begin
  wpi := BeginDeferWindowPos(10);
  Win32Check(wpi <> 0);
  Try
    for i := 1 to 10 do begin
      wnd := (FindComponent('Edit' + IntToStr(i)) as TWinControl).Handle;
      Win32Check(DeferWindowPos(wpi, wnd, 0, 0, 0, 0, 0, Flags) <> 0);
    end;
  Finally
    Win32Check(EndDeferWindowPos(wpi));
  End;
end;

Clearly you'll use a different mechanism to obtain your window handles, but I don't feel that detracts from this example.

Upvotes: 2

Related Questions