What is the best way to create a TPanel with the cross button closed in the upper right corner?

There are several third-party controls (e.g. Raize Components ) that have a closed 'cross' button' button (e.g. page). My requirement is simpler, I would like to cross the 'button' cross in the upper right corner on the TPanel and access its event with a click. Is there an easy way to do this without creating a TPanel descendant, or is there a paid or free library component that I can use?

+7
source share
3 answers

I wrote a control for you.

unit CloseButton; interface uses Windows, Messages, SysUtils, Classes, Controls, UxTheme; type TCloseButton = class(TCustomControl) private FMouseInside: boolean; function MouseButtonDown: boolean; protected procedure Paint; override; procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override; procedure WndProc(var Message: TMessage); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override; public constructor Create(AOwner: TComponent); override; published property Align; property Anchors; property Enabled; property OnClick; property OnMouseUp; property OnMouseDown; end; procedure Register; implementation procedure Register; begin RegisterComponents('Rejbrand 2009', [TCloseButton]); end; { TCloseButton } constructor TCloseButton.Create(AOwner: TComponent); begin inherited; Width := 32; Height := 32; end; function TCloseButton.MouseButtonDown: boolean; begin MouseButtonDown := GetKeyState(VK_LBUTTON) and $8000 <> 0; end; procedure TCloseButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; Invalidate; end; procedure TCloseButton.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited; if not FMouseInside then begin FMouseInside := true; Invalidate; end; end; procedure TCloseButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; Invalidate; end; procedure TCloseButton.Paint; function GetAeroState: cardinal; begin result := CBS_NORMAL; if not Enabled then result := CBS_DISABLED else if FMouseInside then if MouseButtonDown then result := CBS_PUSHED else result := CBS_HOT; end; function GetClassicState: cardinal; begin result := 0; if not Enabled then result := DFCS_INACTIVE else if FMouseInside then if MouseButtonDown then result := DFCS_PUSHED else result := DFCS_HOT; end; var h: HTHEME; begin inherited; if UseThemes then begin h := OpenThemeData(Handle, 'WINDOW'); if h <> 0 then try DrawThemeBackground(h, Canvas.Handle, WP_CLOSEBUTTON, GetAeroState, ClientRect, nil); finally CloseThemeData(h); end; end else DrawFrameControl(Canvas.Handle, ClientRect, DFC_CAPTION, DFCS_CAPTIONCLOSE or GetClassicState) end; procedure TCloseButton.WndProc(var Message: TMessage); begin inherited; case Message.Msg of WM_MOUSELEAVE: begin FMouseInside := false; Invalidate; end; CM_ENABLEDCHANGED: Invalidate; end; end; end. 

Example (with and without themes):

Screen shotScreen shot

Just put it in the TPanel in the upper right corner and install Anchors in the upper and right parts.

+19
source

I am sure you can find a ton of such components available for free Torry or any other similar site ... however, if you need such a function on only one panel, then release the button on the panel, attach it to the upper right corner and do it. If you also want to have a β€œtitle bar” in this panel, then maybe a little more work ...

By the way, if you have JVCL installed, then you already have such a component installed - it is called TjvCaptionPanel or similar.

+4
source

And if you (or anyone else) want to end the TClosePanel (with added additional functionality to distribute the Enabled property using the built-in controls), I wrote one of the following options for you:

 unit ClosePanel; interface USES Windows, Messages, SysUtils, Classes, Controls, ExtCtrls, UxTheme, CloseButton; TYPE TPosition = (posCustom,posTopLeft,posTopCenter,posTopRight,posMiddleRight,posBottomRight,posbottomCenter,posBottomLeft,posMiddleLeft,posCenter); TEnableState = RECORD CTRL : TControl; State : BOOLEAN END; TClosePanel = CLASS(TCustomPanel) CONSTRUCTOR Create(AOwner : TComponent); OVERRIDE; PRIVATE FCloseBtn : TCloseButton; FPosition : TPosition; States : ARRAY OF TEnableState; FAutoEnable : BOOLEAN; PROTECTED PROCEDURE SetEnabled(Value : BOOLEAN); OVERRIDE; PROCEDURE SetParent(Parent : TWinControl); OVERRIDE; PROCEDURE SetPosition(Value : TPosition); VIRTUAL; PROCEDURE MoveCloseButton; VIRTUAL; PROCEDURE WMWindowPosChanged(VAR Message : TWMWindowPosChanged); MESSAGE WM_WINDOWPOSCHANGED; FUNCTION GetOnClose: TNotifyEvent; VIRTUAL; PROCEDURE SetOnClose(Value : TNotifyEvent); VIRTUAL; PUBLIC PROPERTY DockManager; PUBLISHED PROPERTY Align; PROPERTY Alignment; PROPERTY Anchors; PROPERTY AutoSize; PROPERTY AutoEnable : BOOLEAN read FAutoEnable write FAutoEnable default TRUE; PROPERTY BevelEdges; PROPERTY BevelInner; PROPERTY BevelKind; PROPERTY BevelOuter; PROPERTY BevelWidth; PROPERTY BiDiMode; PROPERTY BorderWidth; PROPERTY BorderStyle; PROPERTY Caption; PROPERTY CloseBtn : TCloseButton read FCloseBtn write FCloseBtn; PROPERTY Color; PROPERTY Constraints; PROPERTY Ctl3D; PROPERTY UseDockManager default True; PROPERTY DockSite; PROPERTY DragCursor; PROPERTY DragKind; PROPERTY DragMode; PROPERTY Enabled; PROPERTY FullRepaint; PROPERTY Font; PROPERTY Locked; PROPERTY Padding; PROPERTY ParentBiDiMode; PROPERTY ParentBackground; PROPERTY ParentColor; PROPERTY ParentCtl3D; PROPERTY ParentFont; PROPERTY ParentShowHint; PROPERTY PopupMenu; PROPERTY Position : TPosition read FPosition write SetPosition default posTopRight; PROPERTY ShowHint; PROPERTY TabOrder; PROPERTY TabStop; PROPERTY VerticalAlignment; PROPERTY Visible; PROPERTY OnAlignInsertBefore; PROPERTY OnAlignPosition; PROPERTY OnCanResize; PROPERTY OnClick; PROPERTY OnClose : TNotifyEvent read GetOnClose write SetOnClose; PROPERTY OnConstrainedResize; PROPERTY OnContextPopup; PROPERTY OnDockDrop; PROPERTY OnDockOver; PROPERTY OnDblClick; PROPERTY OnDragDrop; PROPERTY OnDragOver; PROPERTY OnEndDock; PROPERTY OnEndDrag; PROPERTY OnEnter; PROPERTY OnExit; PROPERTY OnGetSiteInfo; PROPERTY OnMouseActivate; PROPERTY OnMouseDown; PROPERTY OnMouseEnter; PROPERTY OnMouseLeave; PROPERTY OnMouseMove; PROPERTY OnMouseUp; PROPERTY OnResize; PROPERTY OnStartDock; PROPERTY OnStartDrag; PROPERTY OnUnDock; END; PROCEDURE Register; IMPLEMENTATION PROCEDURE Register; BEGIN RegisterComponents('HeartWare', [TClosePanel]); END; TYPE TMyCloseBtn = CLASS(TCloseButton) CONSTRUCTOR Create(AOwner : TComponent); OVERRIDE; PROTECTED PROCEDURE WMWindowPosChanged(VAR Message : TWMWindowPosChanged); MESSAGE WM_WINDOWPOSCHANGED; PRIVATE SaveW : INTEGER; SaveH : INTEGER; SaveX : INTEGER; SaveY : INTEGER; END; { TClosePanel } CONSTRUCTOR TClosePanel.Create(AOwner : TComponent); BEGIN INHERITED Create(AOwner); FAutoEnable:=TRUE; FCloseBtn:=TMyCloseBtn.Create(Self); FCloseBtn.Name:='CloseButton'; FCloseBtn.Tag:=1 END; FUNCTION TClosePanel.GetOnClose : TNotifyEvent; BEGIN Result:=CloseBtn.OnClick END; PROCEDURE TClosePanel.MoveCloseButton; PROCEDURE SetPos(ModeX,ModeY : INTEGER); PROCEDURE SetLeft(Value : INTEGER); BEGIN IF FCloseBtn.Left<>Value THEN FCloseBtn.Left:=Value END; PROCEDURE SetTop(Value : INTEGER); BEGIN IF FCloseBtn.Top<>Value THEN FCloseBtn.Top:=Value END; BEGIN CASE ModeX OF -1 : SetLeft(0); 0 : SetLeft((ClientWidth-FCloseBtn.Width) DIV 2); 1 : SetLeft(ClientWidth-FCloseBtn.Width) END; CASE ModeY OF -1 : SetTop(0); 0 : SetTop((ClientHeight-FCloseBtn.Height) DIV 2); 1 : SetTop(ClientHeight-FCloseBtn.Height) END END; BEGIN CASE FPosition OF posTopLeft : SetPos(-1,-1); posTopCenter : SetPos(0,-1); posTopRight : SetPos(1,-1); posMiddleRight : SetPos(1,0); posBottomRight : SetPos(1,1); posbottomCenter : SetPos(0,1); posBottomLeft : SetPos(-1,1); posMiddleLeft : SetPos(-1,0); posCenter : SetPos(0,0) END END; PROCEDURE TClosePanel.SetEnabled(Value : BOOLEAN); PROCEDURE Enable; VAR REC : TEnableState; BEGIN FOR REC IN States DO REC.CTRL.Enabled:=REC.State; SetLength(States,0) END; PROCEDURE Disable; VAR I : Cardinal; CMP : TComponent; REC : TEnableState; BEGIN SetLength(States,0); FOR I:=1 TO ComponentCount DO BEGIN CMP:=Components[PRED(I)]; IF CMP IS TControl THEN BEGIN REC.CTRL:=CMP AS TControl; REC.State:=REC.CTRL.Enabled; REC.CTRL.Enabled:=FALSE; SetLength(States,SUCC(LENGTH(States))); States[HIGH(States)]:=REC END END END; BEGIN IF AutoEnable THEN IF Value THEN Enable ELSE Disable; FCloseBtn.Enabled:=Value; INHERITED SetEnabled(Value) END; PROCEDURE TClosePanel.SetOnClose(Value : TNotifyEvent); BEGIN FCloseBtn.OnClick:=Value END; PROCEDURE TClosePanel.SetParent(Parent : TWinControl); BEGIN INHERITED SetParent(Parent); IF FCloseBtn.Tag=1 THEN BEGIN Position:=posTopRight; FCloseBtn.Tag:=0; Caption:='' END END; PROCEDURE TClosePanel.SetPosition(Value : TPosition); BEGIN FPosition:=Value; MoveCloseButton END; PROCEDURE TClosePanel.WMWindowPosChanged(VAR MESSAGE : TWMWindowPosChanged); BEGIN INHERITED; MoveCloseButton END; { TMyCloseBtn } CONSTRUCTOR TMyCloseBtn.Create(AOwner : TComponent); BEGIN INHERITED Create(AOwner); Width:=16; Height:=16; Parent:=AOwner AS TWinControl END; PROCEDURE TMyCloseBtn.WMWindowPosChanged(VAR Message : TWMWindowPosChanged); BEGIN INHERITED; IF (Parent IS TClosePanel) AND (TClosePanel(Parent).Position<>posCustom) THEN WITH Message.WindowPos^ DO IF (cx<>SaveW) OR (cy<>SaveH) OR (x<>SaveX) OR (y<>SaveY) THEN BEGIN SaveW:=cx; SaveH:=cy; SaveX:=x; SaveY:=y; TClosePanel(Parent).MoveCloseButton END; WITH Message.WindowPos^ DO BEGIN SaveW:=cx; SaveH:=cy; SaveX:=x; SaveY:=y END END; END. 

You can set the position of the Close button (by default I used 16x16 pixels instead of 32x32 by default Andreas) using the TClosePanel.Position property. If you set this value to any other value than posCustom, then it will automatically move around the panel when the panel (or button) resizes. If you install it on posCustom, you will have to manage the placement with the CloseBtn object open. You may then need to modify the Andreas file to show the binding properties, visibility, top, left, width and height. Change the PUBLISHED section in its code to the following:

  published property Anchors; property Enabled; property Height; property Left; property Top; property Visible; property Width; property OnClick; property OnMouseUp; property OnMouseDown; end; 
+4
source

All Articles