Drawing on a Coded Form

A C# Geekpedia page gives a useful introduction to drawing on a form. We have adapted our existing Pascal drawing code and provide here an Oxygene for .Net version. Plasmoid.Extensions (GraphicsExtension.cs) is needed here only for the rounded rectangle.

The form is divided into cells with a horizontal border HB and vertical border VB. CellInnerWidth and CellInnerHeight are the cell dimensions within these borders. The final cell contains a rectangle drawn on a translated, rotated and scaled canvas.

To try this example, start a new Oxygene for .Net console application named OxygenDrawDemo and paste in the code below to replace the default code. Add System.Windows.Forms and System.Drawing to the references. Put GraphicsExtension.cs in the program folder and add it to the project by (1) selecting menu item PROJECT > Add Existing Item..., (2) selecting GraphicsExtension.cs and (3) clicking the "Add" button. Note that it does not matter that this is a .cs rather than a .pas source file. If you do not want the console window to appear, select menu item Projects > OxygenDrawDemo Properties and change the output to Windows Application.

The created window, after clicking the temporary "Draw" button, appears as follows.

Drawing on a Coded Form

Drawing on a Coded Form

Oxygene code

namespace OxygeneDrawDemo;

interface

uses 
  System.Windows.Forms, System.Drawing, // Add these to the references.
  Plasmoid.Extensions; // add existing item GraphicsExtension.cs to the project
type
  CodedForm = static class 
  private 
    f: Form;
    btn: Button;
    g:  Graphics;
    pen1: Pen  := new Pen(Color.Red);
    const HB: Integer = 10;     // Horizontal border
    const VB: Integer = 10;     // Vertical border
    var Count, MaxX, MaxY, Col1, Col2, Col3, Row1, Row2, Row3,  X, Y, CentreX, CentreY, CellInnerWidth,
    CellInnerHeight, Radius: Integer;
  
    PentagonPoints: array[0..5] of Point;
    TrianglePoints: array[0..3] of Point;
  public
    method Main(args: array of String);
    method RenderRow1;
    method RenderRow2;
    method RenderRow3;
    method RenderRow4;
    method btn_Click(sender: Object; e: EventArgs);
  end;
    
implementation

method CodedForm.btn_Click(sender: Object; e :EventArgs);
begin
  g := f.CreateGraphics;
  RenderRow1;
  RenderRow2;
  RenderRow3;
  RenderRow4;
  btn.Visible := false;
end;


method CodedForm.RenderRow1;
begin
  // Red rect
  g.DrawRectangle(Pens.Red, HB, VB, CellInnerWidth, CellInnerHeight);
  // Yellow filled rectangle 
  g.FillRectangle(Brushes.Yellow, Col1 + HB, VB, CellInnerWidth, CellInnerHeight);
  // Green circle needs bounding square
  CentreX := (Col2 + Col3) / 2;
  CentreY := Row1 / 2;
  g.DrawEllipse(Pens.Green, CentreX - Radius, CentreY - Radius, 2 * Radius, 2 * Radius);
  // Blue filled ellipse needs bounding rectangle
  g.FillEllipse(Brushes.Blue, Col3 + HB, VB, CellInnerWidth, CellInnerHeight);     
end;

method CodedForm.RenderRow2;
begin
  // Aqua line (solid)
  pen1.Color := Color.Aqua;
  pen1.Width := 4;
  g.DrawLine(pen1, HB, Row1 + VB, Col1 - HB, Row2 - VB);
  // Teal dashed line
  pen1.Width := 3;
  pen1.DashStyle := System.Drawing.Drawing2D.DashStyle.Dash;
  pen1.Color:= Color.Teal;
  g.DrawLine(pen1, Col1 + HB, Row2 - VB, Col2 - HB, Row1 + VB);
  pen1.DashStyle := System.Drawing.Drawing2D.DashStyle.Solid;
  // White ellipse with dark grey outline
  pen1.Color := Color.DarkGray;
  pen1.Width := 2;
  g.DrawEllipse(pen1, Col2 + HB, Row1 + VB, CellInnerWidth, CellInnerHeight);
  g.FillEllipse(Brushes.White, Col2 + HB + 2, Row1 + VB + 2, CellInnerWidth - 4, CellInnerHeight - 4); 
  // Purple filled circle
  CentreX := (Col3 + MaxX) div 2;
  CentreY := (Row1 + Row2) div 2;
  g.FillEllipse(Brushes.Purple, CentreX - Radius, CentreY - Radius,  2 * Radius, 2 * Radius);
end;

method CodedForm.RenderRow3;
begin
  // Three quarters of lime ellipse
  CentreX := Col1 div 2;
  CentreY := (Row3 + Row2) div 2;       
  g.FillPie(Brushes.Lime, CentreX - Radius, CentreY - Radius, 2 * Radius, 2 * Radius, 0, 270);
  // Dark grey rounded rectangle needs Plasmoid.Extensions 
  // http://www.codeproject.comdivArticlesdiv38436divExtended-Graphics-Rounded-rectangles-Font-metrics
  g.FillRoundedRectangle(Brushes.DarkGray, Col1 + 2 * HB, Row2 + VB, CellInnerWidth, CellInnerHeight, 20);
  // Fuchsia pentagon
  PentagonPoints[0] := new Point((Col3 + Col2) div 2, Row2 + VB);
  PentagonPoints[1] := new Point(Col3 - HB, (Row2 + Row3) div 2);
  PentagonPoints[2] := new Point(Col3 - (Col1 div 3), Row3 - VB);
  PentagonPoints[3] := new Point(Col2 + (Col1 div 3), Row3 - VB);
  PentagonPoints[4] := new Point(Col2 +  HB,(Row2 + Row3) div 2);
  PentagonPoints[5] :=  PentagonPoints[0];
  g.DrawLines(Pens.Fuchsia, PentagonPoints);
  // Red filled triangle
  TrianglePoints[0] := new Point((Col3 + MaxX) div 2, Row2 + VB);
  TrianglePoints[1] := new Point(MaxX - HB, Row3 - VB);
  TrianglePoints[2] := new Point(Col3 + HB, Row3 - VB);
  TrianglePoints[3] := TrianglePoints[0];
  g.FillPolygon(Brushes.Red, TrianglePoints); 
end;

method CodedForm.RenderRow4;
begin
  // Navy arc of ellipse
  g.DrawArc(Pens.Navy, HB, Row3 + VB, CellInnerWidth, CellInnerHeight, 0, 270);
  // Blue text   
  g.DrawString("pp4s.co.uk", new Font("Arial", 16, FontStyle.Bold), Brushes.Blue, Col1 + HB, (Row3 + MaxY) / 2);
  // Maroon curve
  Count := 0;
  X := Col2 + HB;
  Y := Row3 + VB;
  while ( (X <= Col3) and (Y <= MaxY)) do 
    begin
      g.FillRectangle(Brushes.Maroon, X - 1, Y - 1, 2, 2);
      inc(Count);
      X := Col2 + HB + (Count * MaxX ) div 40;
      Y := Row3 + VB + (Count * Count * MaxY) div 150;
    end;
  // Apply translation, rotation and scale to the canvas then draw a green rectangle
  g.TranslateTransform((Col3 + MaxX) div 2, (Row3 + MaxY) div 2);
  g.RotateTransform(25);
  g.ScaleTransform(0.8, 0.8);
  g.FillRectangle(Brushes.DarkGreen, -CellInnerWidth div 2, -CellInnerHeight div 2, CellInnerWidth, CellInnerHeight); 
end;

method CodedForm.Main(args: array of String);
begin
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  //Form
  f := new Form;
  f.Text := "Drawing on a Coded Form with Oxygene for .Net";
  f.SetBounds(400, 200, 500, 400);
  btn := new Button;
  btn.SetBounds(12, 12, 75, 25);
  btn.Text := "Draw";
  btn.Click += new EventHandler(btn_Click);
  f.Controls.Add(btn);
  //InitializeComponent();
  Col1 := f.ClientSize.Width div 4;   //End of column
  Col2 := f.ClientSize.Width div 2;
  Col3 := Col1 + Col2;
  Row1 := f.ClientSize.Height div 4;   //End of row
  Row2 := f.ClientSize.Height div 2;
  Row3 := Row1 + Row2;
  MaxX := f.ClientSize.Width;
  MaxY := f.ClientSize.Height;
  CellInnerWidth := Col1 - 2 * HB;
  CellInnerHeight := Row1 - 2 * VB;
  if (CellInnerWidth < CellInnerHeight) then
    Radius := CellInnerWidth div 2
  else
    Radius := CellInnerHeight div 2;
  Application.Run(f);
end;

end.
Programming - a skill for life!

How to write programs in the Oxygene for .Net dialect of Pascal