Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to temporarily stop a control from being paint?

We have a win control object which moves its clients to some other coordiantes. The problem is, when there are too many children - for example 500 controls - the code is really slow. It must be because of each control being repainted each time I set Left and Top property. So, I want to tell the WinControl object stop being repainted, and after moving all objects to their new positions, it may be painted again (Something like BeginUpdate for memo and list objects). How can I do this? Here's the code of moving the objects; it's quite simple:

for I := 0 to Length(Objects) - 1 do begin
  with Objects[I].Client do begin
    Left := Left + DX;
    Top := Top + DY;
  end;
end;
like image 522
Javid Avatar asked Jan 25 '13 11:01

Javid


1 Answers

As Cosmin Prund explains, the cause for the long duration is not an effect of repainting but of VCL's realignment requisites at control movement. (If it really should take as long as it does, then you might even need to request immediate repaints).

To temporarily prevent realignment and all checks and work for anchors, align settings and Z-order, use DisableAlign and EnableAlign. And halve the count of calls to SetBounds by called it directly:

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
  Control: TControl;
begin
  for I := 0 to 499 do
  begin
    Control := TButton.Create(Self);
    Control.SetBounds((I mod 10) * 40, (I div 10) * 20, 40, 20);
    Control.Parent := Panel1;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  C: TControl;
begin
  // Disable Panel1 paint
  SendMessage(Panel1.Handle, WM_SETREDRAW, Integer(False), 0);  
  Panel1.DisableAlign;
  try
    for I := 0 to Panel1.ControlCount - 1 do
    begin
      C := Panel1.Controls[I];
      C.SetBounds(C.Left + 10, C.Top + 5, C.Width, C.Height);
    end;
  finally
    Panel1.EnableAlign;
    // Enable Panel1 paint  
    SendMessage(Panel1.Handle, WM_SETREDRAW, Integer(True), 0);
    // Update client area   
    RedrawWindow(Panel1.Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_ALLCHILDREN); 
  end;
end;
like image 104
NGLN Avatar answered Sep 22 '22 08:09

NGLN