2014-06-05 2 views
1

내 코드. 구걸하고 빌렸다.사용자 정의 캡션 바 버튼은 성공했지만

unit uFrm_Details; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, 
    System.SysUtils, System.Variants, System.Classes, 
    Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, 
    Vcl.Buttons; 

const 
    BTN_TOP = 10; 

type 
    TFFrm_Details = class(TForm) 
    procedure FormResize(Sender: TObject); 
    private 
    { Private declarations } 
    FDownButton: TRect; 
    FUpButton: TRect; 
    FCloseButton: TRect; 
    FCBMP, FDBMP, FUBMP: TBitmap; 
    FYCaption, FXTtlBit, FYTtlBit: Integer; 
    FHandle: TCanvasDC; 
    procedure DrawTitleButton; 
    procedure DrawFinalize; 
    procedure FoldDown; 
    procedure FoldUp; 
    {Paint-related messages} 
    procedure WMSetText(var Msg: TWMSetText); message WM_SETTEXT; 
    procedure WMNCPaint(var Msg: TWMNCPaint); message WM_NCPAINT; 
    procedure WMNCActivate(var Msg: TWMNCActivate); message WM_NCACTIVATE; 
    {Mouse down-related messages} 
    procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST; 
    procedure WMNCLButtonDown(var Msg: TWMNCLButtonDown); message WM_NCLBUTTONDOWN; 
    procedure WMNCLButtonUp(var Msg: TWMNCLButtonUp); message WM_NCLBUTTONUP; 

    public 
    { Public declarations } 
    end; 

const 
    htCloseBtn = htSizeLast + 100; 
    htDropBtn = htSizeLast + 101; 
    htCloseUpBtn = htSizeLast + 102; 

var 
    FFrm_Details: TFFrm_Details; 

implementation 

{$R *.dfm} 

uses uFrm_Main; 

{ TTitleBtnForm } 

procedure TFFrm_Details.DrawFinalize; 
begin 
    with FCloseButton do 
    Canvas.Draw(Left, Top, FCBMP); 

    with FDownButton do 
    Canvas.Draw(Left, Top, FDBMP); 

    with FUpButton do 
    Canvas.Draw(Left, Top, FUBMP); 

    ReleaseDC(Self.Handle, FHandle); 
    FCBMP.Free; 
    FDBMP.Free; 
    FUBMP.Free; 
    FHandle:= 0; 
end; 

procedure TFFrm_Details.DrawTitleButton; 
begin 
    FXTtlBit:= GetSystemMetrics(SM_CXSIZE); {Button Width} 
    FYTtlBit:= GetSystemMetrics(SM_CYSIZE); {Button Height} 
    FYCaption:= GetSystemMetrics(SM_CYCAPTION); {Caption Height} 

    FCloseButton:= Bounds(Width - FXTtlBit - 5, BTN_TOP, FXTtlBit, FYTtlBit); 
    FDownButton:= Bounds(Width - (2 * FXTtlBit) - 3, BTN_TOP, FXTtlBit, FYTtlBit); 
    FUpButton:= Bounds(Width - (3 * FXTtlBit) - 1, BTN_TOP, FXTtlBit, FYTtlBit); 

    Canvas.Handle := GetWindowDC(Self.Handle); 
    FHandle:= Canvas.Handle; 

    FCBMP:= TBitmap.Create; 
    FDBMP:= TBitmap.Create; 
    FUBMP:= TBitmap.Create; 

end; 

procedure TFFrm_Details.FoldDown; 
begin 
    if ClientHeight = 0 then 
    ClientHeight:= 100; 
end; 

procedure TFFrm_Details.FoldUp; 
begin 
    if ClientHeight > 0 then 
    ClientHeight:= 0; 
end; 

procedure TFFrm_Details.FormResize(Sender: TObject); 
begin 
    inherited; 
    Perform(WM_NCACTIVATE, Word(Active), 0); 
end; 

procedure TFFrm_Details.WMNCActivate(var Msg: TWMNCActivate); 
begin 
    inherited; 

    DrawTitleButton; 

    with FFrm_Main.ImageList1 do 
    begin 
    if Msg.Active = True then 
    begin 
     GetBitmap(1, FCBMP); 
     GetBitmap(5, FDBMP); 
     GetBitmap(9, FUBMP); 
    end 
    else 
    begin 
     GetBitmap(0, FCBMP); 
     GetBitmap(4, FDBMP); 
     GetBitmap(8, FUBMP); 
    end; 
    end; 

    DrawFinalize; 

end; 

procedure TFFrm_Details.WMNCHitTest(var Msg: TWMNCHitTest); 
begin 
    inherited; 

    {Check to see if the mouse was clicked in the area of the button} 
    with Msg do 
    begin 
    if PtInRect(FCloseButton, Point(XPos - Left, YPos - Top)) then 
    begin 
     DrawTitleButton; 

     with FFrm_Main.ImageList1 do 
     begin 
     GetBitmap(2, FCBMP); 
     GetBitmap(5, FDBMP); 
     GetBitmap(9, FUBMP); 
     end; 

     DrawFinalize; 

     Result:= htCloseBtn; 
    end; 

    if PtInRect(FDownButton, Point(XPos - Left, YPos - Top)) then 
    begin 
     DrawTitleButton; 

     with FFrm_Main.ImageList1 do 
     begin 
     GetBitmap(1, FCBMP); 
     GetBitmap(6, FDBMP); 
     GetBitmap(9, FUBMP); 
     end; 

     DrawFinalize; 

     Result:= htDropBtn; 
    end; 

    if PtInRect(FUpButton, Point(XPos - Left, YPos - Top)) then 
    begin 
     DrawTitleButton; 

     with FFrm_Main.ImageList1 do 
     begin 
     GetBitmap(1, FCBMP); 
     GetBitmap(5, FDBMP); 
     GetBitmap(10, FUBMP); 
     end; 

     DrawFinalize; 

     Result:= htCloseUpBtn; 
    end; 
    end; 
end; 

procedure TFFrm_Details.WMNCLButtonDown(var Msg: TWMNCLButtonDown); 
begin 
    inherited; 

    if (Msg.HitTest = htCloseBtn) then 
    begin 
    DrawTitleButton; 

    with FFrm_Main.ImageList1 do 
    begin 
     GetBitmap(3, FCBMP); 
     GetBitmap(5, FDBMP); 
     GetBitmap(10, FUBMP); 
    end; 

    DrawFinalize; 
    end; 

    if (Msg.HitTest = htDropBtn) then 
    begin 
    DrawTitleButton; 

    with FFrm_Main.ImageList1 do 
    begin 
     GetBitmap(1, FCBMP); 
     GetBitmap(7, FDBMP); 
     GetBitmap(10, FUBMP); 
    end; 

    DrawFinalize; 
    end; 

    if (Msg.HitTest = htCloseUpBtn) then 
    begin 
    DrawTitleButton; 

    with FFrm_Main.ImageList1 do 
    begin 
     GetBitmap(1, FCBMP); 
     GetBitmap(5, FDBMP); 
     GetBitmap(11, FUBMP); 
    end; 

    DrawFinalize; 
    end; 

end; 

procedure TFFrm_Details.WMNCLButtonUp(var Msg: TWMNCLButtonUp); 
begin 
    inherited; 
    if (Msg.HitTest = htCloseBtn) then 
    Hide; 

    if (Msg.HitTest = htDropBtn) then 
    FoldDown; 

    if (Msg.HitTest = htCloseUpBtn) then 
    FoldUp; 
end; 

procedure TFFrm_Details.WMNCPaint(var Msg: TWMNCPaint); 
begin 
    inherited; 
    DrawTitleButton; 

    with FFrm_Main.ImageList1 do 
    begin 
    GetBitmap(1, FCBMP); 
    GetBitmap(5, FDBMP); 
    GetBitmap(9, FUBMP); 
    end; 

    DrawFinalize; 

end; 

procedure TFFrm_Details.WMSetText(var Msg: TWMSetText); 
begin 
    inherited; 
    DrawTitleButton; 

    with FFrm_Main.ImageList1 do 
    begin 
    GetBitmap(1, FCBMP); 
    GetBitmap(5, FDBMP); 
    GetBitmap(9, FUBMP); 
    end; 

    DrawFinalize; 
end; 

end. 

지금까지 예상대로 작동합니다. 코드는 완벽하지 않습니다. 더 나은 성능 등을 위해 코드를 조정할 것입니다. 클라이언트 영역에 다른 구성 요소를 놓고 프로그램을 실행합니다. 양식의 클라이언트 영역에는 아무 것도 표시되지 않습니다. 이것은 나를 혼란스럽게합니다.

'OnCreate'이벤트의 클라이언트 영역에 필요한 각 구성 요소를 만들고 'OnDestroy 이벤트'에서 해당 구성 요소를 파괴하면 처음에 클라이언트 영역에 구성 요소를 떨어 뜨린 후에 표시 될 것으로 예상되는 내용을 볼 수 있습니다.

내 질문.

왜 이렇게됩니까? winapi 문서에서 무엇을 놓쳤습니까?

답변

0

귀하의 실수는 API와 관련된 것이 아니라 '캔버스'가 어떻게 작동하는지 간과하는 것입니다.

procedure TFFrm_Details.DrawTitleButton; 
begin 
    ... 
    Canvas.Handle := GetWindowDC(Self.Handle); 
    FHandle:= Canvas.Handle; 
    ... 
end; 

여기서 DC를 검색하여 캔버스 핸들에 할당합니다. 'FHandle'필드는 최적화 할 항목 중 하나입니다.

procedure TFFrm_Details.DrawFinalize; 
begin 
    ... 
    ReleaseDC(Self.Handle, FHandle); 
    FCBMP.Free; 
    FDBMP.Free; 
    FUBMP.Free; 
    FHandle:= 0; 
end; 

여기에서는 캔버스를 불확정 상태로 두었습니다. 알고있는 한 유효한 장치 컨텍스트를 가지고 있습니다. 하지만 그걸 발 밑에서 잡아 당겨. 해결하려면, 0 형태로 스트리밍하는 동안 문제가 저절로 나타난다

... 
    Canvas.Handle := 0; 
    ReleaseDC(Self.Handle, FHandle); 
    ... 


에 캔버스 핸들을 설정합니다. 그래서 런타임에 컨트롤을 만드는 경우 작동합니다.

특히, TCustomForm.ReadState은 글꼴 크기가 컨트롤의 크기를 적절하게 조절하는 시간과 다른지 확인합니다. 잘못된 장치 컨텍스트 핸들을 사용하면 글꼴 높이를 가져올 때 캔바스가 실패합니다. API 호출 GetTextExtentPoint32이 실패하여 VCL에서 반환을 확인하지 않고 캔버스에서 텍스트 높이를 '0'으로보고합니다. 컨트롤은 너비/높이 0으로 적절하게 크기가 조정되어 효과적으로 보이지 않게 렌더링됩니다.

+0

고마워요. 이제는 내 실수를 지적했습니다. 코드의 흥미로운 부분을 살펴본 후 그것을 시험해보고 싶었고 캡션 버튼으로 결과에 만족했지만 클라이언트 영역에 배치 한 구성 요소를 볼 수없는 이유를 알 수 없었습니다. 다시 한번 감사드립니다. – GreenMeanie

+0

@ 그린 - 오신 것을 환영합니다. –