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
Your assumption that the slowness comes from re-painting controls is probably true, but not the whole story. The default Delphi code that handles moving controls would delay painting until the next WM_PAINT
message is received, and that would happen when the message queue is pumped, after you complete moving all the controls. Unfortunately there are a lot of things involved in this, that default behavior can be altered in many places, including Delphi and Windows itself. I've used the following code to test what happens when you move a control at runtime:
var i: Integer;
begin
for i:=1 to 100 do
begin
Panel1.Left := Panel1.Left + 1;
Sleep(10); // Simulate slow code.
end;
end;
The behaviour depends on the control! A TControl
(example: TLabel
) is going to behave according to Delphi's rules, but a TWinControl
depends on too many factors. A simple TPanel
is not repainted until after the loop, in the case of TButton
on my machine only the background is re-painted, while a TCheckBox
is fully repainted. On David's machine the TButton
is also fully repainted, proving this depends on many factors. In the case of TButton
the most likely factor is the Windows version: I tested on Windows 8, David tested on Windows 7.
Anyhow, there's an other really important factor to be taken into account. When you move a control at runtime, all the rules for alignment and anchoring for all the controls need to be taken into account. This likely causes an avalanche of AlignControls
/ AlignControl
/ UpdateAnchorRules
calls. Since all those calls end up requiring recursive invocations of the same, the number of calls will be exponential (hence your observation that moving lots of objects on a TWinControl
is slow).
The simplest solution is, as David suggests, placing everything on a Panel and moving the panel as one. If that's not possible, and all your controls are actually TWinControl
(ie: they have a Window Handle), you could use:
BeginDeferWindowPos, DeferWindowPos, EndDeferWindowPos