How to create a resizable TPanel with a size grip #92
Answer 1
Try this one. It may need some refinement in painting the grip.
unit SizeablePanel; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; type TSizeablePanel = class(TPanel) private FDragging: Boolean; FLastPos: TPoint; protected procedure Paint; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; end; procedure Register; implementation procedure Register; begin RegisterComponents('PBGoodies', [TSizeablePanel]); end; procedure TSizeablePanel.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Button = mbLeft) and ((Width - x ) < 10) and ((Height - y ) < 10) then begin FDragging := TRue; FLastPos := Point(x, y); MouseCapture := true; Screen.cursor := crSizeNWSE; end else inherited; end; procedure TSizeablePanel.MouseMove(Shift: TShiftState; X, Y: Integer); var r: TRect; begin if FDragging then begin r := BoundsRect; SetBounds( r.left, r.top, r.right - r.left + X - FlastPos.X, r.bottom - r.top + Y - Flastpos.Y ); FLastPos := Point( x, y ); end else begin inherited; if ((Width - x ) < 10) and ((Height - y ) < 10) then Cursor := crSizeNWSE else Cursor := crDefault; end; end; procedure TSizeablePanel.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if FDragging then begin FDragging := False; MouseCapture := false; Screen.Cursor := crDefault; end else inherited; end; procedure TSizeablePanel.Paint; var x, y: Integer; begin inherited; Canvas.Font.Name := 'Marlett'; Canvas.Font.Size := 10; Canvas.Brush.Style := bsClear; x := clientwidth - canvas.textwidth('o'); y := clientheight - canvas.textheight('o'); canvas.textout( x, y, 'o' ); end; end.
Tip by Peter Below
Demo code
A ready made project containing this demo code is available. View the project.
In this demo we dynamically create a TSizeablePanel on a form. You will be able to resize it by dragging its size grip with the mouse. Proceed as follows:
- Start a new Delphi VCL application.
-
Create a copy of the SizeablePanel unit presented
above, save it as
SizeablePanel.pas
and add it to the project. -
Name the project's main form "Form1" and create an
OnCreate event handler for TForm1.
Save the form unit as
Unit1.pas
. -
Code
Unit1.pas
as follows:
unit Unit1; interface uses Forms, SizeablePanel; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private fPnl: TSizeablePanel; end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); begin fPnl := TSizeablePanel.Create(Self); fPnl.Parent := Self; fPnl.Top := 20; fPnl.Left := 20; fPnl.Caption := fPnl.ClassName; end; end.
Demo by Peter Johnson
Answer 2
Here's a component that will do that and also looks like it has a statusbar at the bottom:
unit SizeGripPanel; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; type TSizeGripPanel = class(TPanel) private FAllowMove, FAllowSize, FShowSizeGrip: Boolean; procedure SetAllowMove(Value: Boolean); procedure SetAllowSize(Value: Boolean); procedure SetShowSizeGrip(Value: Boolean); protected procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST; procedure Paint; override; published property ShowSizeGrip: Boolean read FShowSizeGrip write SetShowSizeGrip; property AllowMove: Boolean read FAllowMove write SetAllowMove; property AllowSize: Boolean read FAllowSize write SetAllowSize; end; procedure Register; implementation procedure Register; begin RegisterComponents('Samples', [TSizeGripPanel]); end; procedure TSizeGripPanel.WMNCHitTest(var Msg: TWMNCHitTest); var ScreenPt: TPoint; MoveArea: TRect; HANDLE_WIDTH: Integer; SIZEGRIP: Integer; begin {This code came from Lou's Tip of the Day web site ... with changes} HANDLE_WIDTH := BevelWidth; Sizegrip := 19; inherited; if not (csDesigning in ComponentState) then begin ScreenPt := ScreenToClient(Point(Msg.Xpos, Msg.Ypos)); MoveArea := Rect( HANDLE_WIDTH, HANDLE_WIDTH, Width - HANDLE_WIDTH, Height - HANDLE_WIDTH ); if FAllowSize then begin {left side} if (ScreenPt.x < HANDLE_WIDTH) then Msg.Result := HTLEFT {top side} else if (ScreenPt.y < HANDLE_WIDTH) then Msg.Result := HTTOP {right side} else if (ScreenPt.x >= Width - HANDLE_WIDTH) then Msg.Result := HTRIGHT {bottom side} else if (ScreenPt.y >= Height - HANDLE_WIDTH) then Msg.Result := HTBOTTOM {top left corner} else if (ScreenPt.x < Sizegrip) and (ScreenPt.y < Sizegrip) then Msg.Result := HTTOPLEFT {bottom left corner} else if (ScreenPt.x < Sizegrip) and (ScreenPt.y >= Height - Sizegrip) then Msg.Result := HTBOTTOMLEFT {top right corner} else if (ScreenPt.x >= Width - Sizegrip) and (ScreenPt.y < Sizegrip) then Msg.Result := HTTOPRIGHT {bottom right corner} else if (ScreenPt.x >= Width - Sizegrip) and (ScreenPt.y >= Height - Sizegrip) then Msg.Result := HTBOTTOMRIGHT; end; {no sides or corners, this will do the dragging} // !! PJ -> // else // if PtInRect(MoveArea, ScreenPt) and FAllowMove then // Msg.Result := HTCAPTION; if (Msg.Result = HTCLIENT) and PtInRect(MoveArea, ScreenPt) and FAllowMove then Msg.Result := HTCAPTION; // !! PJ <- end; end; procedure TSizeGripPanel.Paint; const Alignments: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER); var Rect: TRect; TopColor, BottomColor: TColor; FontHeight: Integer; LineBeg, LineEnd: TPoint; Flags: Longint; R: TRect; procedure AdjustColors(Bevel: TPanelBevel); begin TopColor := clBtnHighlight; if Bevel = bvLowered then TopColor := clBtnShadow; BottomColor := clBtnShadow; if Bevel = bvLowered then BottomColor := clBtnHighlight; end; procedure DrawCorner(pane: TRect); begin {Got this code from a Codeguru post. It was a CStatusBar descendant and written in C} OffsetRect(pane, - 1, - 1); with Canvas do begin; Canvas.Pen.Color := clBtnHighlight; MoveTo(pane.right - 15, pane.bottom); LineTo(pane.right, pane.bottom - 15); MoveTo(pane.right - 11, pane.bottom); LineTo(pane.right, pane.bottom - 11); MoveTo(pane.right - 7, pane.bottom); LineTo(pane.right, pane.bottom - 7); MoveTo(pane.right - 3, pane.bottom); LineTo(pane.right, pane.bottom - 3); Canvas.Pen.Color := clBtnShadow; MoveTo(pane.right - 14, pane.bottom); LineTo(pane.right, pane.bottom - 14); MoveTo(pane.right - 10, pane.bottom); LineTo(pane.right, pane.bottom - 10); MoveTo(pane.right - 6, pane.bottom); LineTo(pane.right, pane.bottom - 6); MoveTo(pane.right - 2, pane.bottom); LineTo(pane.right, pane.bottom - 2); MoveTo(pane.right - 13, pane.bottom); LineTo(pane.right, pane.bottom - 13); MoveTo(pane.right - 9, pane.bottom); LineTo(pane.right, pane.bottom - 9); MoveTo(pane.right - 5, pane.bottom); LineTo(pane.right, pane.bottom - 5); MoveTo(pane.right - 1, pane.bottom); LineTo(pane.right, pane.bottom); end; end; begin Rect := GetClientRect; if BevelOuter <> bvNone then begin AdjustColors(BevelOuter); Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth); end; Frame3D(Canvas, Rect, Color, Color, BorderWidth); if BevelInner <> bvNone then begin AdjustColors(BevelInner); Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth); end; with Canvas do begin Brush.Color := Color; FillRect(Rect); Brush.Style := bsClear; Font := Self.Font; FontHeight := TextHeight('W'); with Rect do begin Top := ((Bottom + Top) - FontHeight) div 2; Bottom := Top + FontHeight; end; Flags := DT_EXPANDTABS or DT_VCENTER or Alignments[Alignment]; Flags := DrawTextBiDiModeFlags(Flags); DrawText(Handle, PChar(Caption), - 1, Rect, Flags); Rect := GetClientRect; if FShowSizeGrip then begin R := Rect; R.Top := Height - 19; R.Left := Rect.Left + BevelWidth; R.Bottom := Rect.Bottom - BevelWidth; R.Right := Rect.Right - BevelWidth; AdjustColors(BevelOuter); {Always have sunken statusbar! If you want a bar that is raised when your panel is sunken, use this line, instead: Frame3D(Canvas, R, BottomColor, TopColor, 1);} Frame3D(Canvas, R, clBtnShadow, clBtnHighlight, 1); DrawCorner(R); end; end; end; procedure TSizeGripPanel.SetAllowMove(Value: Boolean); begin if Value <> FAllowMove then begin FAllowMove := Value; Invalidate; end; end; procedure TSizeGripPanel.SetAllowSize(Value: Boolean); begin if Value <> FAllowSize then begin FAllowSize := Value; // FShowSizeGrip := Value; !! PJ Invalidate; end; end; procedure TSizeGripPanel.SetShowSizeGrip(Value: Boolean); begin if Value <> FShowSizeGrip then begin FShowSizeGrip := Value; Invalidate; end; end; end.
Tip by Eddie Shipman (with modifications by Peter Johnson)
Demo code
A ready made project containing this demo code is available. View the project.
This demo is similar to the one above. In it we dynamically create a TSizeGripPanel on a form. This time you can change some properties in the form unit to see how the properties affect the panel's behaviour. Proceed as follows:
- Start a new Delphi VCL application.
-
Create a copy of the SizeGripPanel unit presented
above, save it as
SizeGripPanel.pas
and add it to the project. -
Name the project's main form "Form1" and create an
OnCreate event handler for TForm1.
Save the form unit as
Unit1.pas
. -
Code
Unit1.pas
as follows:
unit Unit1; interface uses Forms, SizeGripPanel; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private fPnl: TSizeGripPanel; end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); begin fPnl := TSizeGripPanel.Create(Self); fPnl.Parent := Self; fPnl.Top := 20; fPnl.Left := 20; fPnl.Width := 300; fPnl.Height := 200; fPnl.Caption := fPnl.ClassName; // Change the following properties to see the effect fPnl.AllowMove := True; fPnl.AllowSize := True; fPnl.ShowSizeGrip := True; end; end.
The AllowMove, AllowSize and ShowSizeGrip properties of TSizeGripPanel are set in the FormCreate event handler. They are pretty self-explanatory. Try changing the values of each property (they are all Boolean) and running the demo to see the difference. You should click and drag in the corners, on the edges, in the panel body and on the size grip to see the different effects.
Demo by Peter Johnson
See Tip #93 for a different approach to making a resizeable panel that changes the panel's window style.
Original resource: | The Delphi Pool |
---|---|
Author: | Peter Below & Eddie Shipman |
Added: | 2009/09/07 |
Last updated: | 2010/03/16 |