Delphi – How to draw on a TPanel


I need to draw on a TPanel, ideally directly so I don't have another component on top of it getting in the way of mousevent-event trapping (I want to draw a little "size-grip" on it). How should I go about doing this?

Best Solution

To really do it right, you should probably write a descendant class. Override the Paint method to draw the sizing grip, and override the MouseDown, MouseUp, and MouseMove methods to add resizing functionality to the control.

I think that's a better solution than trying to draw onto a TPanel in your application code for a couple of reasons:

  1. The Canvas property is protected in TPanel, so you have no access to it from outside the class. You can get around that with type-casting, but that's cheating.
  2. The "resizability" sounds more like a feature of the panel than a feature of the application, so put it in code for the panel control, not in your application's main code.

Here's something to get you started:

  TSizablePanel = class(TPanel)
    FDragOrigin: TPoint;
    FSizeRect: TRect;
    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;

procedure TSizeablePanel.Paint;
  // Draw a sizing grip on the Canvas property
  // There's a size-grip glyph in the Marlett font,
  // so try the Canvas.TextOut method in combination
  // with the Canvas.Font property.

procedure TSizeablePanel.MouseDown;
  if (Button = mbLeft) and (Shift = []) 
      and PtInRect(FSizeRect, Point(X, Y)) then begin
    FDragOrigin := Point(X, Y);
    // Need to capture mouse events even if the mouse
    // leaves the control. See also: ReleaseCapture.
  end else inherited;
Related Question