기본 컴포넌트만 써야하는 상황에서
PageControl의 Tab 모양에 변화를 주기위해 Custom으로 그려보았습니다.
uses
.., Vcl.ComCtrls, CommCtrl;
type
TCheckBoxInfo = record
Pos: TPoint;
Width: Integer;
Height: Integer;
Checked: Boolean;
end;
//Developist Custom PageContorl
TPageControl = class(Vcl.ComCtrls.TPageControl)
private
FCheckBoxInfo: TCheckBoxInfo;
protected
//TabControl BackGround
procedure PaintWindow(DC: HDC); override;
//Tab을 그리는 Message를 받아서 처리
procedure CNDrawitem(var Message: TWMDrawItem); message CN_DRAWITEM;
//Border를 그리는 Message를 받아서 처리
procedure TCMAdjustRect(var Msg: TMessage); message TCM_ADJUSTRECT;
public
constructor Create(AOwner: TComponent); override;
end;
type
TForm1 = class(TForm)
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
TabSheet3: TTabSheet;
procedure PageControl1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{ Custom TPageControl }
procedure TPageControl.PaintWindow(DC: HDC);
begin
inherited PaintWindow(DC);
//Custom이 아니면 기본 Style 적용
if not OwnerDraw then Exit;
//TabControl의 Color를 흰색으로 변경(Tab Color가 아님)
FCanvas.Handle := DC;
FCanvas.Brush.Color := clWhite;
FCanvas.FillRect(Self.ClientRect);
end;
procedure TPageControl.CNDrawitem(var Message: TWMDrawItem);
var
Points: array of TPoint;
Rect: TRect;
Rgn: HRGN;
begin
//Tab 영역 가져오기
SelectClipRgn(Message.DrawItemStruct.hDC, 0);
Rect := Message.DrawItemStruct.rcItem;
//Default Tab 그리기(다각형 모양)
SetLength(Points, 0);
SetLength(Points, 4);
Points[0] := Rect.TopLeft;
Points[1].X := Points[0].X + Rect.Width - 10;
Points[0].X := Points[0].X + 10;
Points[1].Y := Points[0].Y;
Points[2] := Rect.BottomRight;
Points[3].X := Points[2].X - Rect.Width;
Points[3].Y := Points[2].Y;
SetDCBrushColor(Message.DrawItemStruct.hDC, clSilver);
Rgn := CreatePolygonRgn(Points[0], 4, ALTERNATE);
FillRgn(Message.DrawItemStruct.hDC, Rgn, GetStockObject(DC_BRUSH));
//Default Tab 그리기(기본 사각형 모양)
//FillRect(Message.DrawItemStruct.hDC, Rect, GetStockObject(DC_BRUSH));
//선택된 Tab은 Highlight 처리
if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then begin
SetDCBrushColor(Message.DrawItemStruct.hDC, clWhite);
SetROP2(Message.DrawItemStruct.hDC, R2_COPYPEN);
SetLength(Points, 0);
SetLength(Points, 4);
Rect.TopLeft.X := Rect.TopLeft.X + 1;
Rect.TopLeft.Y := Rect.TopLeft.Y + 1;
Rect.BottomRight.X := Rect.BottomRight.X - 1;
Rect.BottomRight.Y := Rect.BottomRight.Y;
Points[0].X := Rect.Left + 10;
Points[0].Y := Rect.Top;
Points[1].X := Rect.Right - 10;
Points[1].Y := Rect.Top;
Points[2] := Rect.BottomRight;
Points[3].X := Points[2].X - Rect.Width;
Points[3].Y := Points[2].Y;
Rgn := CreatePolygonRgn(Points[0], 4, ALTERNATE);
FillRgn(Message.DrawItemStruct.hDC, Rgn, GetStockObject(DC_BRUSH));
end;
//Tab Caption 그리기
if Self.Pages[Message.DrawItemStruct.itemID].Tag = 1 then begin
if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then
Rect.Top := Rect.Top + 6
else
Rect.Top := Rect.Top + 5
end else begin
if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then
Rect.Top := (Rect.Height + Canvas.Font.Height) div 2
else
Rect.Top := (Rect.Height + 5 + Canvas.Font.Height) div 2;
end;
SetBkMode(Message.DrawItemStruct.hDC, TRANSPARENT);
DrawText(
Message.DrawItemStruct.hDC,
Self.Pages[Message.DrawItemStruct.itemID].Caption,
Length(Self.Pages[Message.DrawItemStruct.itemID].Caption),
Rect,
DT_CENTER
);
// TextOut(
// Message.DrawItemStruct.hDC,
// (Rect.Left - Length(Self.Pages[Message.DrawItemStruct.itemID].Caption)) div 2,
// Rect.Top + 5,
// PWideChar(Self.Pages[Message.DrawItemStruct.itemID].Caption),
// Length(Self.Pages[Message.DrawItemStruct.itemID].Caption)
// );
//TabSheet의 Tag가 1이면 CheckBox 그리기
if Self.Pages[Message.DrawItemStruct.itemID].Tag = 1 then begin
Rect.Top := Rect.Top + 15;
if Bool(Message.DrawItemStruct.itemState and ODS_SELECTED) then
Rect.Left := Message.DrawItemStruct.rcItem.Left + 18
else
Rect.Left := Message.DrawItemStruct.rcItem.Left + 14;
Rect.Width := 14;
Rect.Height := 14;
FCheckBoxInfo.Pos := Rect.TopLeft;
FCheckBoxInfo.Width := Rect.Width;
FCheckBoxInfo.Height := Rect.Height;
if FCheckBoxInfo.Checked then
DrawFrameControl(
Message.DrawItemStruct.hDC,
Rect,
DFC_BUTTON,
DFCS_BUTTONCHECK or DFCS_CHECKED
)
else
DrawFrameControl(
Message.DrawItemStruct.hDC,
Rect,
DFC_BUTTON,
DFCS_BUTTONCHECK
);
Rect.Left := Rect.Left + 18;
Rect.Width := Message.DrawItemStruct.rcItem.Right - 10;
DrawText(
Message.DrawItemStruct.hDC,
'CheckBoxCaption',
Length('CheckBoxCaption'),
Rect,
DT_LEFT
);
end;
//더 이상 컨트롤하지 못하게 삭제처리
Rgn := CreateRectRgn(0, 0, 0, 0);
SelectClipRgn(Message.DrawItemStruct.hDC, Rgn);
DeleteObject(Rgn);
Message.Result := 1;
inherited;
end;
constructor TPageControl.Create(AOwner: TComponent);
begin
inherited;
//CheckBox 정보
FCheckBoxInfo.Pos := Point(0, 0);
FCheckBoxInfo.Width := 14;
FCheckBoxInfo.Height := 14;
FCheckBoxInfo.Checked := False;
end;
procedure TPageControl.TCMAdjustRect(var Msg: TMessage);
begin
inherited;
//Custom이 아니면 기본 Style 적용
if not OwnerDraw then Exit;
//Border
if Msg.WParam = 0 then begin
with PRect(Msg.LParam)^ do begin
Left := 0;
Right := ClientWidth;
Top := Top - 4;
Bottom := ClientHeight;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//OwnerDraw가 True일 때만 적용됨.
PageControl1.OwnerDraw := True;
end;
procedure TForm1.PageControl1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
//CheckBox 영역 확인
if ((X >= TPageControl(Sender).FCheckBoxInfo.Pos.X) and
(X <= TPageControl(Sender).FCheckBoxInfo.Pos.X + TPageControl(Sender).FCheckBoxInfo.Width)) and
((Y >= TPageControl(Sender).FCheckBoxInfo.Pos.Y) and
(Y <= TPageControl(Sender).FCheckBoxInfo.Pos.Y + TPageControl(Sender).FCheckBoxInfo.Height))
then begin
TPageControl(Sender).FCheckBoxInfo.Checked := not TPageControl(Sender).FCheckBoxInfo.Checked;
TPageControl(Sender).Refresh;
end;
end;
반응형