Reputation: 26660
My control is a TCustomControl
descendant where all the contents is painted with GDI+ in the overridden Paint
method.
Everything is fine when
DoubleBuffered := True;
ParentBackground := False;
and I erase control's background in Paint
method with
g := TGPGraphics.Create(Canvas.Handle);
g.Clear(MakeColor(70, 70, 70));
Now I would like to make a transparent background in the areas where I am not painting.
So, I commented the g.Clear
out and made
ParentBackground := True;
in constructor.
When runtime themes are off it is enough to set DoubleBuffered
of parent control to True
in order to avoid flickering, but with runtime themes this does not help any more.
Below is an excerpt from TWinControl
code with a marked line that causes flickering:
procedure TWinControl.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
if StyleServices.Enabled and Assigned(Parent) and (csParentBackground in FControlStyle) then
begin
{ Get the parent to draw its background into the control's background. }
if Parent.DoubleBuffered then
PerformEraseBackground(Self, Message.DC) //It flickers here!!!!!
else
StyleServices.DrawParentBackground(Handle, Message.DC, nil, False);
end
else
begin
{ Only erase background if we're not doublebuffering or painting to memory. }
if not FDoubleBuffered or
{$IF DEFINED(CLR)}
(Message.OriginalMessage.WParam = Message.OriginalMessage.LParam) then
{$ELSE}
(TMessage(Message).wParam = WPARAM(TMessage(Message).lParam)) then
{$ENDIF}
FillRect(Message.DC, ClientRect, FBrush.Handle);
end;
Message.Result := 1;
end;
Are there any solutions to that?
Upvotes: 2
Views: 684
Reputation: 28516
There is an error in TWinControl.WMEraseBkgnd
method. It should always skip erasing background for double buffered controls when control is not painting in memory.
You can override WMEraseBkgnd
behavior in your own control, or patch TWinControl.WMEraseBkgnd
to apply following fix for all controls.
TMyControl = class(TCustomControl)
protected
...
procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
...
procedure TMyControl.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
{ Only erase background if we're not doublebuffering or painting to memory. }
if not FDoubleBuffered or
{$IF DEFINED(CLR)}
(Message.OriginalMessage.WParam = Message.OriginalMessage.LParam) then
{$ELSE}
(TMessage(Message).WParam = WParam(TMessage(Message).LParam)) then
{$ENDIF}
begin
if StyleServices.Enabled and Assigned(Parent) and (csParentBackground in ControlStyle) then
begin
if Parent.DoubleBuffered then
PerformEraseBackground(Self, Message.DC)
else
StyleServices.DrawParentBackground(Handle, Message.DC, nil, False);
end
else
FillRect(Message.DC, ClientRect, Brush.Handle);
end;
Message.Result := 1;
end;
Issue is reported as RSP-24415
Upvotes: 2