Как нарисовать часть элемента справа налево (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 (справа налево)?


person DmitryB    schedule 24.11.2012    source источник


Ответы (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 темы рисует треугольник шириной 6 пикселей с размером детали 16 пикселей (W7-aero). Поскольку вы не сможете узнать расположение изображения в детали, вы не сможете лучше его выровнять.

person Sertac Akyuz    schedule 25.11.2012

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

давно этим не занимался, так что точно не помню

person MIRV    schedule 25.11.2012