Избегайте мерцания в прозрачном элементе управления, пока включены темы времени выполнения - PullRequest
1 голос
/ 30 апреля 2019

Мой элемент управления является потомком TCustomControl, где все содержимое окрашено с помощью GDI + в переопределенном методе Paint.

Все нормально, когда

DoubleBuffered := True;
ParentBackground := False;

и я стираю фон элемента управления в методе Paint с помощью

g := TGPGraphics.Create(Canvas.Handle);
g.Clear(MakeColor(70, 70, 70));

Теперь я хотел бы сделать прозрачный фон в областях, где я не рисую.

Итак, я прокомментировал g.Clear и сделал

ParentBackground := True;

в конструкторе.

Когда темы выполнения выключены, достаточно установить DoubleBuffered родительского элемента управления на True, чтобы избежать мерцания, но с темами выполнения это больше не помогает.

Ниже приведен фрагмент кода TWinControl с отмеченной линией, которая вызывает мерцание:

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;

Есть ли какие-нибудь решения для этого?

1 Ответ

2 голосов
/ 07 мая 2019

Ошибка в методе TWinControl.WMEraseBkgnd. Следует всегда пропускать стирание фона для элементов управления с двойной буферизацией, когда элемент управления не рисует в памяти.

Вы можете переопределить поведение WMEraseBkgnd в своем собственном элементе управления или установить исправление TWinControl.WMEraseBkgnd, чтобы применить следующее исправление для всех элементов управления.

  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;
...