2010-02-04 28 views
8

如何爲Firefox的TPageControl的TTabsheet實現關閉按鈕?如何爲TPageControl的TTabsheet實現關閉按鈕

編輯:
德爾福版本:德爾福2010
操作系統:Windows XP及以上

+0

德爾福版本? – ulrichb 2010-02-04 18:55:00

+0

你是什麼風格?每個標籤都有自己的按鈕,還是最右邊有一個按鈕適用於當前活動標籤的樣式? – 2010-02-04 19:50:56

+0

@Rob是的,每個標籤上有一個關閉按鈕 – 2010-02-04 19:56:31

回答

31

現在有了主題支持(包括Windows, UxTheme, Themes單位)!

type 
    TFormMain = class(TForm) 
    {...} 
    private 
    FCloseButtonsRect: array of TRect; 
    FCloseButtonMouseDownIndex: Integer; 
    FCloseButtonShowPushed: Boolean; 
    {...} 
    end; 

{...} 

procedure TFormMain.FormCreate(Sender: TObject); 
var 
    I: Integer; 
begin 
    PageControlCloseButton.TabWidth := 150; 
    PageControlCloseButton.OwnerDraw := True; 

    //should be done on every change of the page count 
    SetLength(FCloseButtonsRect, PageControlCloseButton.PageCount); 
    FCloseButtonMouseDownIndex := -1; 

    for I := 0 to Length(FCloseButtonsRect) - 1 do 
    begin 
    FCloseButtonsRect[I] := Rect(0, 0, 0, 0); 
    end; 
end; 

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; 

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

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

     ThemeServices.DrawElement(PageControl.Canvas.Handle, CloseBtnDrawDetails, 
     FCloseButtonsRect[TabIndex]); 
    end; 
    end; 
end; 

procedure TFormMain.PageControlCloseButtonMouseDown(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    I: Integer; 
    PageControl: TPageControl; 
begin 
    PageControl := Sender as TPageControl; 

    if Button = mbLeft then 
    begin 
    for I := 0 to Length(FCloseButtonsRect) - 1 do 
    begin 
     if PtInRect(FCloseButtonsRect[I], Point(X, Y)) then 
     begin 
     FCloseButtonMouseDownIndex := I; 
     FCloseButtonShowPushed := True; 
     PageControl.Repaint; 
     end; 
    end; 
    end; 
end; 

procedure TFormMain.PageControlCloseButtonMouseMove(Sender: TObject; 
    Shift: TShiftState; X, Y: Integer); 
var 
    PageControl: TPageControl; 
    Inside: Boolean; 
begin 
    PageControl := Sender as TPageControl; 

    if (ssLeft in Shift) and (FCloseButtonMouseDownIndex >= 0) then 
    begin 
    Inside := PtInRect(FCloseButtonsRect[FCloseButtonMouseDownIndex], Point(X, Y)); 

    if FCloseButtonShowPushed <> Inside then 
    begin 
     FCloseButtonShowPushed := Inside; 
     PageControl.Repaint; 
    end; 
    end; 
end; 

procedure TFormMain.PageControlCloseButtonMouseLeave(Sender: TObject); 
var 
    PageControl: TPageControl; 
begin 
    PageControl := Sender as TPageControl; 
    FCloseButtonShowPushed := False; 
    PageControl.Repaint; 
end; 

procedure TFormMain.PageControlCloseButtonMouseUp(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    PageControl: TPageControl; 
begin 
    PageControl := Sender as TPageControl; 

    if (Button = mbLeft) and (FCloseButtonMouseDownIndex >= 0) then 
    begin 
    if PtInRect(FCloseButtonsRect[FCloseButtonMouseDownIndex], Point(X, Y)) then 
    begin 
     ShowMessage('Button ' + IntToStr(FCloseButtonMouseDownIndex + 1) + ' pressed!'); 

     FCloseButtonMouseDownIndex := -1; 
     PageControl.Repaint; 
    end; 
    end; 
end; 

的樣子:

page control with buttons

+0

看起來很不錯。截圖是一個很好的接觸!不幸的是,它看起來只適用於Windows 2000或非主題的XP?Vista/7。你有一個使用主題API的版本嗎? – 2010-02-04 23:06:07

+1

@David M:完成。 – ulrichb 2010-02-05 00:27:07

+0

我測試了你的代碼,它運行良好。所以我選擇你的代碼作爲答案。但由於其他featuers我需要我決定使用Jedi JVCL TJvTabBar與littel修改TJvTabBarXPPainter。 – 2010-02-05 02:39:20

3

我過去所做的只是把一個TBitBtn與在TPageControl的右上角的圖形。 TBitBtn的父親的技巧與TPageControl相同,因此它實際上並不在標籤頁之一上。然後在點擊該按鈕,即使該按鈕:

PageControl1.ActivePage.Free; 

噹噹前TTabControl被釋放它會通知它擁有它的TPageControl。

6

正如其他答案所建議的那樣,自己實現這一點通常是一個好主意。但是,如果您已經在使用Raize Components,那麼此功能是「開箱即用」支持的。只需設置TRzPageControl.ShowCloseButtonOnActiveTab := true,並處理OnClose事件。該組件負責爲各種標籤佈局/方向/形狀/顏色進行佈局。

[只是一個快樂的客戶]

0

我已經改變了一點這個例子: - 創建的類TCloseTabSheet - 這個類屬性的OnClose:TNotifyEvent,如果分配 將其稱之爲 - 如果標籤頁TPageControl的是不是那個類,那麼沒有關閉按鈕 - 如果它然後按鈕顯示。當你按下關閉按鈕它調用的OnClose - 現在你不需要控制陣列FCloseButtonsRect,導致此Rects儲存在TCloseTabSheet

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ComCtrls, Themes, Math, ExtCtrls, StdCtrls; 

type TCloseTabSheet=class(TTabSheet) 
    private 
    protected 
    FCloseButtonRect: TRect; 
    FOnClose: TNotifyEvent; 
    procedure DoClose; virtual; 
    public 
    constructor Create(AOwner:TComponent); override; 
    destructor Destroy; override; 
property OnClose:TNotifyEvent read FOnClose write FOnClose; 
end; 

type 
    TMainForm = class(TForm) 
    PageControlCloseButton: TPageControl; 
    TabSheet1: TTabSheet; 
    TabSheet2: TTabSheet; 
    TabSheet3: TTabSheet; 
    procedure FormCreate(Sender: TObject); 
    procedure PageControlCloseButtonDrawTab(Control: TCustomTabControl; TabIndex: Integer; 
     const Rect: TRect; Active: Boolean); 
    procedure PageControlCloseButtonMouseDown(Sender: TObject; 
     Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
    procedure PageControlCloseButtonMouseMove(Sender: TObject; 
     Shift: TShiftState; X, Y: Integer); 
    procedure PageControlCloseButtonMouseLeave(Sender: TObject); 
    procedure PageControlCloseButtonMouseUp(Sender: TObject; 
     Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
    procedure CloseTabeProc(Sender: TObject); 
    private 
    FCloseButtonMouseDownTab: TCloseTabSheet; 
    FCloseButtonShowPushed: Boolean; 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    MainForm: TMainForm; 

implementation 

{$R *.dfm} 

constructor TCloseTabSheet.Create(AOwner:TComponent); 
begin 
    inherited Create(AOwner); 
    FCloseButtonRect:=Rect(0, 0, 0, 0); 
end; 

destructor TCloseTabSheet.Destroy; 
begin 
    inherited Destroy; 
end; 

procedure TCloseTabSheet.DoClose; 
begin 
    if Assigned(FOnClose) then FOnClose(Self); 
    Free; 
end; 

procedure TMainForm.CloseTabeProc(Sender: TObject); 
begin 
    ShowMessage('close'); 
end; 

procedure TMainForm.FormCreate(Sender: TObject); 
var I: Integer; 
    NT:TCloseTabSheet; 
begin 
    PageControlCloseButton.TabWidth := 150; 
    PageControlCloseButton.OwnerDraw := True; 
    NT:=TCloseTabSheet.Create(PageControlCloseButton); 
    NT.Caption:='TabSheet4'; 
    NT.PageControl:=PageControlCloseButton; 
    NT.OnClose:=CloseTabeProc; 

    FCloseButtonMouseDownTab := nil; 
end; 

procedure TMainForm.PageControlCloseButtonDrawTab(Control: TCustomTabControl; 
    TabIndex: Integer; const Rect: TRect; Active: Boolean); 
var 
    CloseBtnSize: Integer; 
    PageControl: TPageControl; 
    TabSheet:TCloseTabSheet; 
    TabCaption: TPoint; 
    CloseBtnRect: TRect; 
    CloseBtnDrawState: Cardinal; 
    CloseBtnDrawDetails: TThemedElementDetails; 
begin 
    PageControl := Control as TPageControl; 
    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; 
    if PageControl.Pages[TabIndex] is TCloseTabSheet then 
    begin 
    TabSheet:=PageControl.Pages[TabIndex] as TCloseTabSheet; 
    CloseBtnSize := 14; 

    CloseBtnRect.Bottom := CloseBtnRect.Top + CloseBtnSize; 
    CloseBtnRect.Left := CloseBtnRect.Right - CloseBtnSize; 
    TabSheet.FCloseButtonRect := CloseBtnRect; 

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

    if not ThemeServices.ThemesEnabled then 
    begin 
     if (FCloseButtonMouseDownTab = TabSheet) and FCloseButtonShowPushed then 
     CloseBtnDrawState := DFCS_CAPTIONCLOSE + DFCS_PUSHED 
     else 
     CloseBtnDrawState := DFCS_CAPTIONCLOSE; 

     Windows.DrawFrameControl(PageControl.Canvas.Handle, 
     TabSheet.FCloseButtonRect, DFC_CAPTION, CloseBtnDrawState); 
    end 
    else 
    begin 
     Dec(TabSheet.FCloseButtonRect.Left); 

     if (FCloseButtonMouseDownTab = TabSheet) and FCloseButtonShowPushed then 
     CloseBtnDrawDetails := ThemeServices.GetElementDetails(twCloseButtonPushed) 
     else 
     CloseBtnDrawDetails := ThemeServices.GetElementDetails(twCloseButtonNormal); 

     ThemeServices.DrawElement(PageControl.Canvas.Handle, CloseBtnDrawDetails, 
       TabSheet.FCloseButtonRect); 
    end; 
    end else begin 
    PageControl.Canvas.FillRect(Rect); 
    PageControl.Canvas.TextOut(TabCaption.X, TabCaption.Y, 
       PageControl.Pages[TabIndex].Caption); 
    end; 
end; 

procedure TMainForm.PageControlCloseButtonMouseDown(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    I: Integer; 
    PageControl: TPageControl; 
    TabSheet:TCloseTabSheet; 
begin 
    PageControl := Sender as TPageControl; 

    if Button = mbLeft then 
    begin 
    for I := 0 to PageControl.PageCount - 1 do 
    begin 
     if not (PageControl.Pages[i] is TCloseTabSheet) then Continue; 
     TabSheet:=PageControl.Pages[i] as TCloseTabSheet; 
     if PtInRect(TabSheet.FCloseButtonRect, Point(X, Y)) then 
     begin 
     FCloseButtonMouseDownTab := TabSheet; 
     FCloseButtonShowPushed := True; 
     PageControl.Repaint; 
     end; 
    end; 
    end; 
end; 

procedure TMainForm.PageControlCloseButtonMouseLeave(Sender: TObject); 
var 
    PageControl: TPageControl; 
begin 
    PageControl := Sender as TPageControl; 
    FCloseButtonShowPushed := False; 
    PageControl.Repaint; 
end; 

procedure TMainForm.PageControlCloseButtonMouseMove(Sender: TObject; 
    Shift: TShiftState; X, Y: Integer); 
var 
    PageControl: TPageControl; 
    Inside: Boolean; 
begin 
    PageControl := Sender as TPageControl; 

    if (ssLeft in Shift) and Assigned(FCloseButtonMouseDownTab) then 
    begin 
    Inside := PtInRect(FCloseButtonMouseDownTab.FCloseButtonRect, Point(X, Y)); 

    if FCloseButtonShowPushed <> Inside then 
    begin 
     FCloseButtonShowPushed := Inside; 
     PageControl.Repaint; 
    end; 
    end; 
end; 

procedure TMainForm.PageControlCloseButtonMouseUp(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    PageControl: TPageControl; 
begin 
    PageControl := Sender as TPageControl; 

    if (Button = mbLeft) and Assigned(FCloseButtonMouseDownTab) then 
    begin 
    if PtInRect(FCloseButtonMouseDownTab.FCloseButtonRect, Point(X, Y)) then 
    begin 
     FCloseButtonMouseDownTab.DoClose; 
     FCloseButtonMouseDownTab := nil; 
     PageControl.Repaint; 
    end; 
    end; 
end; 

end.