2014-12-19 3 views
1

자식 창에서 GDI +를 사용하여 문자열을 그릴 때 텍스트가 나타나지 않습니다. 그러나 자식 창을 일반 창으로 변경하면 텍스트가 정상적으로 나타납니다. 그래서 여기 는 내가 지금까지했던 것입니다 :Win API Delphi 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. 

텍스트가 나타납니다 정상 창에 자식 창을 변경!

코드에서 :

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

사람 :

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

텍스트가 그려집니다! 정확히 무엇이 문제입니까? 전체 자식 창이 아닌 텍스트 만 표시되기 때문에 자식 창을 WS_EX_LAYERED로 유지하고 싶습니다.

+0

이러한 가로 스크롤 막대는 사용하지 않습니다. 더 친숙한 독자가되도록 편집 해주십시오. –

+0

편집 한 것처럼 방금 만들었습니다. 주 프로그램 코드에서 동일한 작업을 수행하는 것에 신경을 써야 할 수도 있습니다. –

+0

고마워 .... –

답변

2

UpdateLayeredWindow은 하위 창과 최상위 창에서만 지원됩니다.

그러나 Windows 8에서 MS는 다른 창에 대한 지원도 추가했습니다.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms633556%28v=vs.85%29.aspx

보통, 오히려 여기 드로잉 GDI +를 사용하여 투명 VCL 맞춤 제어를 생성하기위한 기본 코드 (NO 예외 처리)이다. 그것은 개념의 증거이며 직접 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; 
+0

UpdateLayeredWindow를 사용하지 않고 다른 해결책이 있습니까? –

+0

창을 투명하게 만들어 그 아래에있는 창을 먼저 그린 다음 WM_PAINT (또는 OnPaint 이벤트)에 코드를 그립니다. WM_ERASEBKGND 메시지를 비활성화해야 할 수 있습니다. –

+0

GDI + 드로잉을 처리하는 투명 VCL 컨트롤을 만들었습니다. 내 WinAPI 기술은 지금 약간 녹슬었고 그래서 나는 더 쉬운 길을 사용했다. –

관련 문제