[Lazarus] Adding shapes to TShape

Frederic Da Vitoria davitofrg at gmail.com
Thu Dec 26 14:26:00 CET 2013


2013/12/26 Howard Page-Clark <hdpc at talktalk.net>

> On 26/12/2013 12:03, Frederic Da Vitoria wrote:
>   Should I
>
>> forget about deriving TShape and should I directly modify TShape's code?
>>
>
> For a project that needed something similar I found that TShape with its
> fixed TShapeType enumeration was too inflexible (though it is
> Delphi-compatible, hence its presence).
> Trying to stuff too much shape-drawing code variety into one gloriously
> polymorphic control becomes increasingly complex and difficult to maintain.
> I ended up writing a simple (isosceles only) triangle control which you
> are welcome to adapt as suits you, attached here.
>
> unit triangles;
>
> {$mode objfpc}{$H+}
>
> interface
>
> uses
>   Classes, Controls, types, Graphics, LCLProc;
>
> type
>   {$M+}
>   TBaseAlign=(baBottom, baTop, baLeft, baRight);
>   {$M+}
>
>   { TTriangle }
>
>   TTriangle=class(TGraphicControl)
>   private
>     FPen: TPen;
>     FBaseAlign: TBaseAlign;
>     FBrush: TBrush;
>     procedure SetBrush(Value: TBrush);
>     procedure SetPen(Value: TPen);
>     procedure SetBaseAlign(aValue: TBaseAlign);
>   protected
>     class function GetControlClassDefaultSize: TSize; override;
>   public
>     constructor Create(TheOwner: TComponent); override;
>     destructor Destroy; override;
>     procedure Paint; override;
>     procedure ParamsChanged(Sender: TObject);
>   published
>     property Align;
>     property Anchors;
>     property BaseAlign: TBaseAlign read FBaseAlign write SetBaseAlign
> default baBottom;
>     property BorderSpacing;
>     property Brush: TBrush read FBrush write SetBrush;
>     property Constraints;
>     property DragCursor;
>     property DragKind;
>     property DragMode;
>     property Enabled;
>     property ParentShowHint;
>     property Pen: TPen read FPen write SetPen;
>     property OnChangeBounds;
>     property OnDragDrop;
>     property OnDragOver;
>     property OnEndDock;
>     property OnEndDrag;
>     property OnMouseDown;
>     property OnMouseMove;
>     property OnMouseUp;
>     property OnPaint;
>     property OnResize;
>     property OnStartDock;
>     property OnStartDrag;
>     property ShowHint;
>     property Visible;
>   end;
>
> implementation
>
> { TTriangle }
>
> procedure TTriangle.SetBrush(Value: TBrush);
> begin
>   if Value <> Brush then
>     FBrush.Assign(Value);
> end;
>
> procedure TTriangle.SetPen(Value: TPen);
> begin
>    if Value <> Pen then
>     FPen.Assign(Value);
> end;
>
> procedure TTriangle.SetBaseAlign(aValue: TBaseAlign);
> begin
>   if aValue<>FBaseAlign then begin
>     FBaseAlign:=aValue;
>     ParamsChanged(Self);
>   end;
> end;
>
> class function TTriangle.GetControlClassDefaultSize: TSize;
> begin
>   Result.cx:=65;
>   Result.cy:=65;
> end;
>
> constructor TTriangle.Create(TheOwner: TComponent);
> begin
>   inherited Create(TheOwner);
>   with GetControlClassDefaultSize do
>     SetInitialBounds(0, 0, CX, CY);
>   ControlStyle := ControlStyle + [csReplicatable];
>   FPen := TPen.Create;
>   FPen.OnChange := @ParamsChanged;
>   FBrush := TBrush.Create;
>   FBrush.OnChange := @ParamsChanged;
>   FBaseAlign:=baBottom;
> end;
>
> destructor TTriangle.Destroy;
> begin
>   FreeThenNil(FPen);
>   FreeThenNil(FBrush);
>   inherited Destroy;
> end;
>
> procedure TTriangle.Paint;
> var
>   PaintRect: TRect;
>   P: array[1..3] of TPoint;
>   PenInc, PenDec: Integer;
>
>   procedure CalcPoints(aBaseAlign: TBaseAlign);
>   begin
>     case aBaseAlign of
>       baBottom: begin P[1].x := (Width - 1) div 2;
>         P[1].y := PenInc;
>         P[2].x := Width - PenInc - 1;
>         P[2].y := Height - PenInc - 1;
>         P[3].x := PenInc;
>         P[3].y := Height - PenInc - 1;  end;
>       baTop: begin P[3].x := (Width - 1) div 2;
>         P[1].x := PenInc;
>         P[2].x := Width - PenInc - 1;
>         P[3].y := Height - PenInc - 1;
>         P[1].y := PenInc;
>         P[2].y := PenInc;  end;
>       baLeft: begin P[1].x := PenInc;
>         P[1].y := PenInc;
>         P[2].x := Width - PenInc - 1;
>         P[2].y := (Height - 1) div 2;
>         P[3].x := PenInc;
>         P[3].y := Height - PenInc - 1;  end;
>       baRight: begin P[1].y := (Height - 1) div 2;
>         P[1].x := PenInc;
>         P[2].x := Width - PenInc - 1;
>         P[2].y := PenInc;
>         P[3].x := Width - PenInc - 1;
>         P[3].y := Height - PenInc - 1;  end;
>     end;
>   end;
>
> begin
>   Canvas.Pen:=FPen;
>   Canvas.Brush:=FBrush;
>
>   PenInc := Pen.Width div 2;
>   PenDec := (Pen.Width - 1) div 2;
>
>   PaintRect := Rect(PenInc, PenInc, Self.Width - PenDec, Self.Height -
> PenDec);
>   if PaintRect.Left = PaintRect.Right then
>     PaintRect.Right := PaintRect.Right + 1;
>   if PaintRect.Top = PaintRect.Bottom then
>     PaintRect.Bottom := PaintRect.Bottom + 1;
>
>   CalcPoints(FBaseAlign);
>   Canvas.Polygon(P);
>
>   inherited Paint;
> end;
>
> procedure TTriangle.ParamsChanged(Sender: TObject);
> begin
>   if (Parent <> nil) and (Visible or (csDesigning in ComponentState)) and
>      Parent.HandleAllocated then
>     Invalidate;
> end;
>
> end.
>

Isoceles is quite enough for my needs. It should be easy to add squares,
rectangles and circles (although of course I'll have the change the class'
name)

Thank you, Howard

-- 
Frederic Da Vitoria
(davitof)

Membre de l'April - « promouvoir et défendre le logiciel libre » -
http://www.april.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20131226/fa1ca904/attachment-0003.html>


More information about the Lazarus mailing list