2012-05-10 8 views
4

이 예제에서 제공된 코드 How to implement a close button for a TTabsheet of a TPageControl을 사용하여 pagecontrol의 각 탭 시트에 닫기 버튼을 그려서 ThemeServices를 코드 내부의 스타일 서비스로 대체했으며 스타일 적용시 닫기 버튼이 전혀 보이지 않고 반응하지 않습니다. 누구든지이 문제를 해결하는 다른 길로 나를 안내 할 수 있습니까? 고맙습니다! 당신은 VCL 스타일을 사용하는 경우vcl 스타일을 지원하지 않는 탭 시트의 닫기 버튼

procedure TFormMain.PageControlCloseButtonDrawTab(Control: TCustomTabControl; 
    TabIndex: Integer; const Rect: TRect; Active: Boolean); 
var 
    CloseBtnSize: Integer; 
    PageControl: TPageControl; 
    TabCaption: TPoint; 
    CloseBtnRect: TRect; 
    CloseBtnDrawState: Cardinal; 
    CloseBtnDrawDetails: TThemedElementDetails; 
begin 
    PageControl := Control as TPageControl; 

    if InRange(TabIndex, 0, Length(FCloseButtonsRect) - 1) then 
    begin 
    CloseBtnSize := 14; 
    TabCaption.Y := Rect.Top + 3; 

    if Active then 
    begin 
     CloseBtnRect.Top := Rect.Top + 4; 
     CloseBtnRect.Right := Rect.Right - 5; 
     TabCaption.X := Rect.Left + 6; 
    end 
    else 
    begin 
     CloseBtnRect.Top := Rect.Top + 3; 
     CloseBtnRect.Right := Rect.Right - 5; 
     TabCaption.X := Rect.Left + 3; 
    end; 

    CloseBtnRect.Bottom := CloseBtnRect.Top + CloseBtnSize; 
    CloseBtnRect.Left := CloseBtnRect.Right - CloseBtnSize; 
    FCloseButtonsRect[TabIndex] := CloseBtnRect; 

    PageControl.Canvas.FillRect(Rect); 
    PageControl.Canvas.TextOut(TabCaption.X, TabCaption.Y, PageControl.Pages[TabIndex].Caption); 

    if not UseThemes then 
    begin 
     if (FCloseButtonMouseDownIndex = TabIndex) and FCloseButtonShowPushed then 
     CloseBtnDrawState := DFCS_CAPTIONCLOSE + DFCS_PUSHED 
     else 
     CloseBtnDrawState := DFCS_CAPTIONCLOSE; 

     Winapi.Windows.DrawFrameControl(PageControl.Canvas.Handle, 
     FCloseButtonsRect[TabIndex], DFC_CAPTION, CloseBtnDrawState); 
    end 
    else 
    begin 
     Dec(FCloseButtonsRect[TabIndex].Left); 

     if (FCloseButtonMouseDownIndex = TabIndex) and FCloseButtonShowPushed then 
     CloseBtnDrawDetails := StyleServices.GetElementDetails(twCloseButtonPushed) 
     else 
     CloseBtnDrawDetails := StyleServices.GetElementDetails(twCloseButtonNormal); 

     StyleServices.DrawElement(PageControl.Canvas.Handle, CloseBtnDrawDetails, 
     FCloseButtonsRect[TabIndex]); 
    end; 
    end; 
end; 
+0

VCL 스타일에는 자체 DrawTab 메소드가 있기 때문입니다. 당신은 당신 자신의 VCL 스타일 훅을 만들고 거기에 추가 버튼을 그려야합니다. – TLama

답변

11

, 당신은, 탭 컨트롤에 닫기 버튼을 그리는 Vcl.Styles.ColorTabs 유닛을 살펴하는 VCL 스타일의 후크를 작성해야합니다 (소개 : 이것은 OnDrawTab 이벤트의 코드 이 기사에서 Creating colorful tabsheets with the VCL Styles, Added border to TTabColorControlStyleHook)이 스타일 훅을 작성하는 데 필요한 아이디어가 있습니다. 탭에 단추를 그리는 코드를 추가하면 단추 상태 (보통, 높음)를 변경하고 닫기 단추에서 클릭을 감지하기 위해 스타일 훅에서 WM_MOUSEMOVE 및 WM_LBUTTONUP 메시지를 처리해야합니다.

스타일 훅 구현에 문제가 있으면 여기에서 전체 솔루션을 게시 해주세요.

UPDATE는

난 그냥 tabsheets에 닫기 버튼에 대한 suport를 추가하려면이 간단한 스타일의 후크를 썼다.

uses 
    Vcl.Styles, 
    Vcl.Themes; 

type 
    TTabControlStyleHookBtnClose = class(TTabControlStyleHook) 
    private 
    FHotIndex  : Integer; 
    FWidthModified : Boolean; 
    procedure WMMouseMove(var Message: TMessage); message WM_MOUSEMOVE; 
    procedure WMLButtonUp(var Message: TWMMouse); message WM_LBUTTONUP; 
    function GetButtonCloseRect(Index: Integer):TRect; 
    strict protected 
    procedure DrawTab(Canvas: TCanvas; Index: Integer); override; 
    procedure MouseEnter; override; 
    procedure MouseLeave; override; 
    public 
    constructor Create(AControl: TWinControl); override; 
    end; 

constructor TTabControlStyleHookBtnClose.Create(AControl: TWinControl); 
begin 
    inherited; 
    FHotIndex:=-1; 
    FWidthModified:=False; 
end; 

procedure TTabControlStyleHookBtnClose.DrawTab(Canvas: TCanvas; Index: Integer); 
var 
    Details : TThemedElementDetails; 
    ButtonR : TRect; 
    FButtonState: TThemedWindow; 
begin 
    inherited; 

    if (FHotIndex>=0) and (Index=FHotIndex) then 
    FButtonState := twSmallCloseButtonHot 
    else 
    if Index = TabIndex then 
    FButtonState := twSmallCloseButtonNormal 
    else 
    FButtonState := twSmallCloseButtonDisabled; 

    Details := StyleServices.GetElementDetails(FButtonState); 

    ButtonR:= GetButtonCloseRect(Index); 
    if ButtonR.Bottom - ButtonR.Top > 0 then 
    StyleServices.DrawElement(Canvas.Handle, Details, ButtonR); 
end; 

procedure TTabControlStyleHookBtnClose.WMLButtonUp(var Message: TWMMouse); 
Var 
    LPoint : TPoint; 
    LIndex : Integer; 
begin 
    LPoint:=Message.Pos; 
    for LIndex := 0 to TabCount-1 do 
    if PtInRect(GetButtonCloseRect(LIndex), LPoint) then 
    begin 
     if Control is TPageControl then 
     begin 
     TPageControl(Control).Pages[LIndex].Parent:=nil; 
     TPageControl(Control).Pages[LIndex].Free; 
     end; 
     break; 
    end; 
end; 

procedure TTabControlStyleHookBtnClose.WMMouseMove(var Message: TMessage); 
Var 
    LPoint : TPoint; 
    LIndex : Integer; 
    LHotIndex : Integer; 
begin 
    inherited; 
    LHotIndex:=-1; 
    LPoint:=TWMMouseMove(Message).Pos; 
    for LIndex := 0 to TabCount-1 do 
    if PtInRect(GetButtonCloseRect(LIndex), LPoint) then 
    begin 
     LHotIndex:=LIndex; 
     break; 
    end; 

    if (FHotIndex<>LHotIndex) then 
    begin 
    FHotIndex:=LHotIndex; 
    Invalidate; 
    end; 
end; 

function TTabControlStyleHookBtnClose.GetButtonCloseRect(Index: Integer): TRect; 
var 
    FButtonState: TThemedWindow; 
    Details : TThemedElementDetails; 
    R, ButtonR : TRect; 
begin 
    R := TabRect[Index]; 
    if R.Left < 0 then Exit; 

    if TabPosition in [tpTop, tpBottom] then 
    begin 
    if Index = TabIndex then 
     InflateRect(R, 0, 2); 
    end 
    else 
    if Index = TabIndex then 
    Dec(R.Left, 2) 
    else 
    Dec(R.Right, 2); 

    Result := R; 
    FButtonState := twSmallCloseButtonNormal; 

    Details := StyleServices.GetElementDetails(FButtonState); 
    if not StyleServices.GetElementContentRect(0, Details, Result, ButtonR) then 
    ButtonR := Rect(0, 0, 0, 0); 

    Result.Left :=Result.Right - (ButtonR.Width) - 5; 
    Result.Width:=ButtonR.Width; 
end; 

procedure TTabControlStyleHookBtnClose.MouseEnter; 
begin 
    inherited; 
    FHotIndex := -1; 
end; 

procedure TTabControlStyleHookBtnClose.MouseLeave; 
begin 
    inherited; 
    if FHotIndex >= 0 then 
    begin 
    FHotIndex := -1; 
    Invalidate; 
    end; 
end; 

이 방법

TStyleManager.Engine.RegisterStyleHook(TCustomTabControl, TTabControlStyleHookBtnClose); 
    TStyleManager.Engine.RegisterStyleHook(TTabControl, TTabControlStyleHookBtnClose); 

에 등록이 데모를하다

enter image description here

+0

안녕하세요 로드리고, TLama가 나에게 다투는 순간 맞춤 스타일 훅을 구현하려고했지만이 물건에 압도 당합니다. vcl 스타일의 것은 블로그를 제외하고는 많은 문서를 찾을 수 없다는 것입니다. 나는 몇 가지 예제를 시도했지만, 독자적으로 처리 할 수는 없다. 나는 또한 윈도우 메시지 처리에 관한 자료가 필요하다. 나는 구글을 다시 보게 될 것이다. 그리고 독서의 약간의 시간 후에 나는 또 다른 시도를 할 것이다. 조언에 감사한다. –

+0

데모와 완전히 다르게 작동하지만 나를 위해 일했습니다. 우선, 그들은 나를 위해 레이블을 겹칩니다. 두 번째로 탭 위로 마우스를 가져 가면 나타납니다. 셋째, 그들은 실제로 아주 작게 나타납니다. Silver 스타일의 XE7 사용. 그 차이점은 스타일에 의해 통제됩니까? –

+0

사실 그들은 기본적으로 평면으로 표시하고 텍스트가 겹치기 때문에 볼 수 없습니다. 전체 버튼이 보이게하려면 작은'x'를 가져 가야합니다. 또한 각 캡션 끝에 5 칸을 추가해야했습니다. Uggg :-) http://i.imgbox.com/YHlCTt13.png –

0

필자는이 예에서 일하고, 나는 그것을 델파이의 메트로 UI 작업있어 XE6.

는 탭 이름과 버튼 사이의 정확한 거리를 얻기를위한 나의 해결 방법은이 라인

Result.Left := Result.Right - (ButtonR.Width); 
//it was Result.Left := Result.Right - (ButtonR.Width) -5; 

그리고 PageController의 특성에 더 큰 TabWith ​​설정을 수정했다.

또한 "Register"라인이 유닛의 끝 부분 바로 앞에있는 초기화 클래스에 있음을 상기하십시오.

//...all the code of the unit 

Initialization 

TStyleManager.Engine.RegisterStyleHook(TCustomTabControl, 
    TTabControlStyleHookBtnClose); 
TStyleManager.Engine.RegisterStyleHook(TTabControl, 
    TTabControlStyleHookBtnClose); 

end.//final unit "end" =D