Delphi: How to diagnose a sluggish interface?
I have a form that you can pretend to have laid out as Windows Explorer:
- Panel
- left
- Separator
-
client panel
+------------+#+-----------------------+ | |#| | | |#| | | |#| | | |#| | | Left |#| Client | | |#| | | |#| | | |#| | | |#| | | |#| | +------------+#+-----------------------+ ^ | +----splitter
On the left and in the client area pane, each one has controls.
The problem is that using the splitter is very sluggish. I would expect a modern 2GHz computer to be able to re-render the shape as quickly as a human can click a mouse. But this is definitely not the case, and it takes about 200-300ms before the shape is fully corrected.
The form contains about 100 visual controls, no code or custom controls.
How do I know who is causing the slowness?
source to share
Use a profiler. Eric Grange The sampler sampler is good. AutomatedQA AQtime is great.
This is more than likely due to repeated resizing and redrawing as the controls adjust their layouts and sizes. A lot of nesting or just a lot of controls in general can cause problems. You can avoid this by overriding AlignControls
and only adjusting the alignment once every time the divider is moved, but it will involve quite a bit of work.
Alternatively, TSplitter has a property ResizeStyle
that controls the immediate movement of controls or XOR'd string across the form, and controls are only updated at the end. Not so visually pleasing, but much less work.
source to share
Make a test version of your form, remove all controls and keep only the panels and dividers. Make sure performance is still sluggish.
Put some non-blocking messages (to file, console debugger, gexperts debugger) in resize events. Are you only getting a few, as you would expect, or dozens?
The left pane and splitter should be aligned with alLeft and the other with alClient.
source to share
This is mainly due to the renaming of the events of these many controls
You can try disabling the background in your form (reduces the amount of colors):
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
...
procedure TfrmBaseMain.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
Message.Result := 1;
end;
source to share