Как нарисовать часть элемента в направлении справа налево (RTL) при рисовании с DrawThemeBackground?

Я пытаюсь нарисовать ttGlyphClosed элемент Explorer::Treeview класс в направлении справа налево (например, когда BiDiMode было бы bdLeftToRight). У меня проблема в том, что я не знаю, как сделать мой закадровый рисунок прозрачным. Фон растрового изображения всегда белый.

Я использую следующий код для зеркального отображения изображения:

procedure TForm5.FormPaint(Sender: TObject);
var
  bm: TBitmap;
  ARect: TRect;
  Details: TThemedElementDetails;
begin    
  if ExplorerTreeviewhTheme = 0 then
    ExplorerTreeviewhTheme := OpenThemeData(0, 'Explorer::Treeview');

  ARect := Rect(20, 20, 40, 40);
  Details := ThemeServices.GetElementDetails(ttGlyphClosed);
  DrawThemeBackground(ExplorerTreeviewhTheme, Canvas.Handle,
    Details.Part, Details.State, ARect, nil); //Ok

  bm := TBitmap.Create;
  try
    bm.Width := 20;
    bm.Height := 20;

    ARect := Rect(00, 00, 20, 20);
    DrawThemeBackground(ExplorerTreeviewhTheme, bm.Canvas.Handle,
      Details.Part, Details.State, ARect, nil);

    // rendered result has white background
    Canvas.Draw(60, 10, bm);    
    // rendered result is mirrored but has also white background
    StretchBlt(Canvas.Handle, 100, 10, -20, 20, bm.Canvas.Handle, 0, 0, 20, 20, SRCCOPY);
  finally
    bm.Free;
  end;    
end;

Вопрос в том, как отразить элемент, нарисованный DrawThemeBackground функция (для чтения RTL) или как использовать эту функцию для рендеринга RTL (справа налево)?

2 ответа

Решение

Использование SetLayout как показал TLama в своем теперь удаленном ответе, чтобы переключить макет холста перед рисованием.

function SetLayout(hdc: HDC; dwLayout: DWORD): DWORD; stdcall;
  external 'gdi32' name 'SetLayout';

const
  LAYOUT_RTL = $00000001;

procedure TForm1.FormPaint(Sender: TObject);
var
  ExplorerTreeviewhTheme: HTHEME;
  Details: TThemedElementDetails;
  ARect: TRect;
  Size: TSize;
begin
  ExplorerTreeviewhTheme := OpenThemeData(Handle, 'Explorer::Treeview');
  Details := ThemeServices.GetElementDetails(ttGlyphClosed);
  GetThemePartSize(ExplorerTreeviewhTheme, Canvas.Handle, Details.Part,
      Details.State, nil, TS_DRAW, Size);

  ARect := Rect(20, 30, 20 + Size.cx, 30 + Size.cy);

  // normal layout
  DrawThemeBackground(ExplorerTreeviewhTheme, Canvas.Handle,
                      Details.Part, Details.State, ARect, nil);

  // switched layout
  SetLayout(Canvas.Handle, LAYOUT_RTL);

  // calculate the rectangle for RTL as if it's in LTR
  OffsetRect(ARect, 0, Size.cy); // align to the bottom of the first image so that we can see
  ARect.Left := ClientWidth - ARect.Left - Size.cx;
  ARect.Right := ARect.Left + Size.cx;

  DrawThemeBackground(ExplorerTreeviewhTheme, Canvas.Handle,
                      Details.Part, Details.State, ARect, nil);

  // restore layout
  SetLayout(Canvas.Handle, 0);
  CloseThemeData(ExplorerTreeviewhTheme);
end;

Выход:

API темы рисует треугольник шириной 6px в размере 16px (W7-aero). Поскольку вы не сможете узнать расположение изображения в детали, вы не сможете выровнять его лучше.

Вы используете srccopy в своем вызове stretchblt, но я думаю, что вам может понадобиться поискать альтернативы, в том числе, возможно, использование маски

я не делал этого на некоторое время, поэтому точно не помню

Другие вопросы по тегам