Say you have a form that you can expand to the left to show additional controls:
Collapsed:
Expanded:
The simplest way to achieve this in Delphi is to use alRight
as the primary anchor for all controls (instead of alLeft
) and then simply adjust the width and X coordinate of the form. Either you can set the Width
and Left
properties individually, or you can use a function that sets them simultaneously, like
if FCollapsed then
SetWindowPos(Handle, 0, Left - Width, Top, 2 * Width, Height, 0)
else
SetWindowPos(Handle, 0, Left + Width div 2, Top, Width div 2, Height, 0)
The problem is that there is quite noticeable flickering in the always-visible part of the form (in this example, the buttons) while expanding or collapsing. Try it yourself!
It is possible for the operating system to resize the form to the left without any flickering at all -- just grab the left edge of the form using the mouse and drag the mouse to the left or right -- but I am unable to find any function in the Windows API that exposes this kind of resizing.
I have tried to use several different Windows API functions to resize and reposition the form, tried their various parameters (for instance, the SWP_*
flags), tried LockWindowUpdate
, WM_SETREDRAW
, TForm.DoubleBuffered
etc. to no avail. I also examined the possibility to use the WM_SYSCOMMAND
SC_SIZE
approach.
I am not yet sure if the problem lies at the OS level or the VCL level.
Any suggestions?
Edit: I am very surprised to see that this Q received close votes. Let me try to clarify:
Create a new VCL forms application.
Add a few buttons to the right side of the main form and a memo to the left. Set
Anchors
to[alTop, alRight]
on all controls. On theOnClick
handler of the buttons, add the following code:if FCollapsed then SetWindowPos(Handle, 0, Left - Width, Top, 2 * Width, Height, 0) else SetWindowPos(Handle, 0, Left + Width div 2, Top, Width div 2, Height, 0); FCollapsed := not FCollapsed;
where
FCollapsed
is private boolean field of the form (initialized tofalse
).Now, click the buttons repeatedly. (Or give one of them keyboard focus and hold the Enter key for a few seconds.) You will probably notice that the region with the buttons on your monitor will not display a perfect still image, but will flicker. In addition, you might actually see 'ghosts' of the buttons to the left of the actual column of buttons.
I am unable to capture this millisecond flickering using screen capture, so instead I used a digital camera to record my screen:
https://privat.rejbrand.se/VCLFormExpandFlicker.mp4
In this video clip, it is apparent that the column of buttons isn't a static image on the screen; instead, for a few milliseconds each time the form is resized, this region is something else than it should be. It is equally apparent that there is a 'ghost' column of buttons to the left.
My question is if there is any reasonably simple way to get rid of these visual artefacts (that at least to me are very visible even if you expand/collapse the form a single time).
On my Windows 10/Delphi 10.1 computer at work, the form is resized in a perfect manner when I drag its left-most edge using the mouse: the unaffected client area of the form is perfectly static on the monitor. However, on my Windows 7/Delphi 2009 PC at home, I do see that there is a lot of repositioning going on when I do this.
DisableAlign
/EnableAlign
? – CuckooflowerAlign
to[alTop, alRight]
on all controls and use the code I submitted. You can useTForm.OnClick
, for example, and toggleFCollapsed
on each invocation. The WM_COMMAND-style resizing is flicker-free at least on Windows 10 with visual themes enabled. I can imagine it not being flicker-free on Windows 7 without visual themes (but I haven't tested). – PeccantWM_ERASEBKGND
message as it might be the root cause of the flicker. – Pooleprocedure TForm2.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin if Collapsing then Sleep(200); inherited; end;
– CuckooflowerWM_ERASEBKGND
, but it didn't improve the situation. – Peccant