[Lazarus] Adding shapes to TShape
Howard Page-Clark
hdpc at talktalk.net
Thu Dec 26 14:21:17 CET 2013
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.
More information about the Lazarus
mailing list