Win API Delphi GDI+;:在子窗口中绘制字符串

Win API Delphi GDI+;:在子窗口中绘制字符串,delphi,winapi,gdi+,transparent,drawstring,Delphi,Winapi,Gdi+,Transparent,Drawstring,在子窗口中使用GDI+绘制字符串时,文本不会显示。 但是,当我将子窗口更改为普通窗口时,文本将正常显示。所以这里 这就是我到目前为止所做的: program Test_Program; Uses Windows, Messages, GdipObj, GdipApi, DirectDraw; var Msg: TMSG; LWndClass: TWndClass; hMainHandle: HWND; Function CreateChildWi

在子窗口中使用GDI+绘制字符串时,文本不会显示。 但是,当我将子窗口更改为普通窗口时,文本将正常显示。所以这里 这就是我到目前为止所做的:

program Test_Program;

 Uses
   Windows,
   Messages,
   GdipObj,
   GdipApi,
   DirectDraw;

var
  Msg: TMSG;
  LWndClass: TWndClass;
  hMainHandle: HWND;

Function CreateChildWindow(hParent: hWnd): hWnd;
Var
  WindowClass: TWndClass;
Begin
  Result := 0;
  WindowClass.lpszClassName := 'ChildWindow';
  WindowClass.Style := cs_HRedraw or cs_VRedraw;
  WindowClass.lpfnWndProc := @DefWindowProc;
  WindowClass.cbClsExtra := 0;
  WindowClass.cbWndExtra := 0;
  WindowClass.hInstance := HInstance;
  WindowClass.hIcon := LoadIcon(0, idi_Application);
  WindowClass.hCursor := LoadCursor(0, idc_Arrow);
  WindowClass.hbrBackground := COLOR_BTNFACE + 1;
  WindowClass.lpszMenuName := NIL;
  WindowClass.lpszClassName := 's';
  if RegisterClass(WindowClass)<>0 Then
    Result := CreateWindowEx(WS_EX_CONTROLPARENT or WS_EX_LAYERED, 
      WindowClass.lpszClassName, '', WS_CHILD or WS_VISIBLE or WS_SYSMENU 
      or WS_CAPTION, 0, 0, 400, 300, hParent, 0, hInstance, nil);
End;

Function MainFormProc(hWnd, Msg: LongInt; wParam: WPARAM; lParam: LPARAM):LongInt;
  stdcall;
var ChildhWnd: Integer;
    Author : String;
    AuthorPosX, AuthorPosY: Single;
    SrcDC, DestDC: HDC;
    BitmapHandle, PrevBitmap: HBITMAP;
    BlendFunc: _BLENDFUNCTION;
    Size: TSize;
    POSS: TRect;
    P, S: TPoint;
    Graphics  : TGPGraphics;
    Bitmap    : TGPBitmap;
    Font      : TGPFont;
    FontFamily: TGPFontFamily;
    SolidBrush: TGPSolidBrush;
Begin
  Result := 0;
  Case Msg of
    WM_CREATE:
    Begin
      SolidBrush := TGPSolidBrush.Create($FF000000);
      FontFamily := TGPFontFamily.Create('Arial');
      Font       := TGPFont.Create(FontFamily, 18, FontStyleRegular, UnitPixel);

      ChildhWnd := CreateChildWindow(hWnd);

      Author    := 'Transparent Child Window + GDI+ Text';
      AuthorPosX:= 30;
      AuthorPosY:= 40;
      Size.cx := 600;
      Size.cy := 80;

      Bitmap   := TGPBitmap.Create(600, 80, PixelFormat32bppARGB);
      Graphics := TGPGraphics.Create(Bitmap);
      Graphics.SetTextRenderingHint(TextRenderingHintAntiAlias); {Set Text Anti Aliased}
      S.X := 0;
      S.Y := 0;
      With BlendFunc Do
      Begin
        BlendOp := AC_SRC_ALPHA;
        BlendFlags := 0;
        SourceConstantAlpha := 250;
        AlphaFormat := AC_SRC_ALPHA;
      End;
      Graphics.Clear(0);
      Graphics.DrawString(Author, Length(Author), Font,
      MakePoint(AuthorPosX, AuthorPosY), SolidBrush);
      SrcDC := CreateCompatibleDC(0);
      DestDC:= CreateCompatibleDC(SrcDC);
      Bitmap.GetHBITMAP(0, BitmapHandle);
      PrevBitmap := SelectObject(SrcDC, BitmapHandle);
      GetWindowRect(ChildhWnd, POSS);
      P.X := POSS.Left;
      P.Y := POSS.Top;
      UpdateLayeredWindow(ChildhWnd, DestDC, @P, @Size, SrcDC, 
        @S, 0, @BlendFunc, ULW_ALPHA);
      SelectObject(SrcDC, PrevBitmap);
      DeleteObject(BitmapHandle);
      DeleteDC(DestDC);
      DeleteDC(SrcDC);
      ShowWindow(ChildhWnd, CmdShow);
      UpdateWindow(ChildhWnd);

    End;

    WM_LBUTTONDOWN:
    Begin
      DefWindowProc(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
      Result:=0;
    End;
    WM_DESTROY: ExitProcess(0);
  else
    Result := DefWindowProc(hWnd, Msg, wParam, lParam);
  end;
end;

begin
  LWndClass.hInstance := hInstance;
  with LWndClass do
  begin
    lpszClassName := 'TMainForm';
    Style := CS_PARENTDC or CS_BYTEALIGNCLIENT;
    hIcon := LoadIcon(hInstance, 'MAINICON');
    lpfnWndProc := @MainFormProc;
    hbrBackground := COLOR_BTNFACE + 1;
    hCursor := LoadCursor(0, IDC_ARROW);
  end;

  RegisterClass(LWndClass);
  hMainHandle := CreateWindow(LWndClass.lpszClassName, 'Main Window',
    WS_SYSMENU, (GetSystemMetrics(SM_CXSCREEN)  div 2) - 400,
    (GetSystemMetrics(SM_CYSCREEN) div 2) - 300, 800, 600, 
    0, 0, hInstance,  nil);

  ShowWindow(hMainHandle, SW_SHOW);
  UpdateWindow(hMainHandle);

  while GetMessage(Msg, 0, 0, 0) do
  begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
end.
致:

文本将被绘制!!到底是什么问题?
顺便说一句,我希望子窗口保持WS_EX_分层,因为我只希望文本显示在整个子窗口中。

UpdateLayeredWindow
仅支持顶级窗口,而不支持子窗口

然而,在Windows8中,MS也增加了对其他Windows的支持

好的,下面是创建透明VCL自定义控件的基本代码(无异常处理),该控件使用GDI+进行绘图。它是概念验证,并且可以转换回直接Windows API

type
  TPWinControl = class(TWinControl);

  TTransparentControl = class(TCustomControl)
  protected
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  end;

function GetScreenClient(Control: TControl): TPoint;
var
  p: TPoint;
begin
  p := Control.ClientOrigin;
  ScreenToClient(Control.Parent.Handle, p);
  Result := p;
end;

procedure TTransparentControl.WMEraseBkgnd(var Message: TWmEraseBkgnd);
var
  Bmp: TBitmap;
  DC: hDC;
  i: integer;
  p: TPoint;

  Author: string;
  AuthorPosX, AuthorPosY: Single;
  Size: TSize;
  Graphics: TGPGraphics;
  Bitmap: TGPBitmap;
  Font: TGPFont;
  FontFamily: TGPFontFamily;
  SolidBrush: TGPSolidBrush;
begin
  message.Result := 1;
  if (message.DC <> 0) and Assigned(Parent) then
    begin
      DC := message.DC;
      i := SaveDC(DC);
      p := GetScreenClient(Self);
      MoveWindowOrg(DC, -p.x, -p.y);
      SendMessage(Parent.Handle, WM_ERASEBKGND, DC, 0);
      TPWinControl(Parent).PaintControls(DC, nil);
      RestoreDC(DC, i);

      Bmp := TBitmap.Create;
      Bmp.PixelFormat := pf32bit;
      Bmp.Width := Width;
      Bmp.Height := Height;
      BitBlt(Bmp.Canvas.Handle, 0, 0, Width, Height, DC, 0, 0, SrcCopy);

      SolidBrush := TGPSolidBrush.Create($FF000000);
      FontFamily := TGPFontFamily.Create('Arial');
      Font := TGPFont.Create(FontFamily, 18, FontStyleRegular, UnitPixel);
      Author := 'Transparent Child Window + GDI+ Text';
      AuthorPosX := 30;
      AuthorPosY := 40;
      Size.cx := 600;
      Size.cy := 80;

      Bitmap := TGPBitmap.Create(Bmp.Handle);
      Graphics := TGPGraphics.Create(Bmp.Canvas.Handle);
      Graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);
      Graphics.DrawString(Author, Length(Author), Font, 
        MakePoint(AuthorPosX, AuthorPosY), SolidBrush);
      Graphics.Free;
      Bitmap.Free;
      Canvas.Draw(0, 0, Bmp);
      Bmp.Free;
    end;
end;
类型
TPWinControl=等级(TWinControl);
tttransparentcontrol=class(TCustomControl)
受保护的
程序WMEraseBkgnd(var消息:TWmEraseBkgnd);消息WM_ERASEBKGND;
结束;
函数GetScreenClient(控件:TControl):TPoint;
变量
p:TPoint;
开始
p:=Control.ClientOrigin;
ScreenToClient(Control.Parent.Handle,p);
结果:=p;
结束;
过程TTTransparentControl.WMEraseBkgnd(var消息:TWmEraseBkgnd);
变量
Bmp:TBitmap;
DC:hDC;
i:整数;
p:TPoint;
作者:字符串;
AuthorPosX,AuthorPosY:单个;
大小:TSize;
图形:TGPGraphics;
位图:TGPBitmap;
字体:TGPFont;
FontFamily:TGPFontFamily;
SolidBrush:TGPSolidBrush;
开始
消息。结果:=1;
如果(message.DC.0)和已分配(父级),则
开始
DC:=message.DC;
i:=SaveDC(DC);
p:=GetScreenClient(Self);
移动窗口组织(DC,-p.x,-p.y);
SendMessage(Parent.Handle,WM_ERASEBKGND,DC,0);
TPWinControl(主)、PaintControls(直流、无);
恢复性糖尿病(DC,i);
Bmp:=TBitmap.Create;
Bmp.PixelFormat:=pf32位;
Bmp.Width:=宽度;
Bmp.Height:=高度;
BitBlt(Bmp.Canvas.Handle,0,0,宽度,高度,DC,0,0,srcopy);
SolidBrush:=TGPSolidBrush.Create($FF000000);
FontFamily:=TGPFontFamily.Create('Arial');
Font:=TGPFont.Create(FontFamily,18,FontStyleRegular,UnitPixel);
作者:='透明子窗口+GDI+文本';
AuthorPosX:=30;
作者:=40;
Size.cx:=600;
Size.cy:=80;
位图:=TGPBitmap.Create(Bmp.Handle);
Graphics:=TGPGraphics.Create(Bmp.Canvas.Handle);
Graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);
图形.抽绳(作者、长度(作者)、字体、,
生成点(AuthorPosX、AuthorPosY)、SolidBrush);
图形。免费;
位图。免费;
绘制(0,0,Bmp);
Bmp.Free;
结束;
结束;

那些水平滚动条令人讨厌。请你编辑一下,让它更容易阅读。就像我刚才做的编辑一样。您可能会考虑对主程序代码执行同样的操作。我认为这里不需要真正的子窗口。什么是父窗口?您不使用VCL窗体和控件是否有原因?>“到底是什么问题?”>-第一个-最重要的-问题是您没有检查错误
CreateWindowEx
返回0,您甚至没有子窗口-更不用说缺少文本了。。。这是因为您指定了
WS_EX_LAYERED
样式-请参阅文档。是否有其他不使用UpdateLayeredWindow的解决方案?请使窗口透明,以便首先绘制其下方的窗口,然后在WM_PAINT(或OnPaint事件)中绘制代码。您可能需要禁用WM_橡皮擦BKGND消息。我制作了透明VCL控件,用于处理GDI+绘图。我的WinAPI技能目前有点生疏,所以我使用了更简单的方法。
CreateWindowEx(WS_EX_CONTROLPARENT or WS_EX_LAYERED, 
  WindowClass.lpszClassName, '', 
  WS_VISIBLE or WS_SYSMENU or WS_CAPTION, 
  0, 0, 400, 300, hParent, 0, hInstance, nil);
type
  TPWinControl = class(TWinControl);

  TTransparentControl = class(TCustomControl)
  protected
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  end;

function GetScreenClient(Control: TControl): TPoint;
var
  p: TPoint;
begin
  p := Control.ClientOrigin;
  ScreenToClient(Control.Parent.Handle, p);
  Result := p;
end;

procedure TTransparentControl.WMEraseBkgnd(var Message: TWmEraseBkgnd);
var
  Bmp: TBitmap;
  DC: hDC;
  i: integer;
  p: TPoint;

  Author: string;
  AuthorPosX, AuthorPosY: Single;
  Size: TSize;
  Graphics: TGPGraphics;
  Bitmap: TGPBitmap;
  Font: TGPFont;
  FontFamily: TGPFontFamily;
  SolidBrush: TGPSolidBrush;
begin
  message.Result := 1;
  if (message.DC <> 0) and Assigned(Parent) then
    begin
      DC := message.DC;
      i := SaveDC(DC);
      p := GetScreenClient(Self);
      MoveWindowOrg(DC, -p.x, -p.y);
      SendMessage(Parent.Handle, WM_ERASEBKGND, DC, 0);
      TPWinControl(Parent).PaintControls(DC, nil);
      RestoreDC(DC, i);

      Bmp := TBitmap.Create;
      Bmp.PixelFormat := pf32bit;
      Bmp.Width := Width;
      Bmp.Height := Height;
      BitBlt(Bmp.Canvas.Handle, 0, 0, Width, Height, DC, 0, 0, SrcCopy);

      SolidBrush := TGPSolidBrush.Create($FF000000);
      FontFamily := TGPFontFamily.Create('Arial');
      Font := TGPFont.Create(FontFamily, 18, FontStyleRegular, UnitPixel);
      Author := 'Transparent Child Window + GDI+ Text';
      AuthorPosX := 30;
      AuthorPosY := 40;
      Size.cx := 600;
      Size.cy := 80;

      Bitmap := TGPBitmap.Create(Bmp.Handle);
      Graphics := TGPGraphics.Create(Bmp.Canvas.Handle);
      Graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);
      Graphics.DrawString(Author, Length(Author), Font, 
        MakePoint(AuthorPosX, AuthorPosY), SolidBrush);
      Graphics.Free;
      Bitmap.Free;
      Canvas.Draw(0, 0, Bmp);
      Bmp.Free;
    end;
end;