delphiellipseonpaintpaintbox

Drawing an ellipse with 360 degree graduations


I have drawn a graduated ellipse on my form using the paint box. The only problem is that I have used Moveto and LineTo many times to grade the ellipse.

procedure PaintBox1Paint(Sender: TObject);
begin
 paintbox1.canvas.Pen.Color := clblue;
 paintbox1.canvas.Pen.Width := 1;
 paintbox1.canvas.Ellipse(98,51,520,473);
 paintbox1.canvas.MoveTo(515,263);
 paintbox1.canvas.LineTo(526,263);
 paintbox1.canvas.MoveTo(310,45);
 paintbox1.canvas.LineTo(310,52);              
 paintbox1.canvas.MoveTo(90,263);
 paintbox1.canvas.LineTo(99,263);
 paintbox1.canvas.MoveTo(310,472);
 paintbox1.canvas.LineTo(310,479);
 paintbox1.canvas.MoveTo(512,207);              
 paintbox1.canvas.LineTo(518,206);
 paintbox1.canvas.MoveTo(491,158);
 paintbox1.canvas.LineTo(496,155);
 paintbox1.canvas.MoveTo(458,114);
 paintbox1.canvas.LineTo(462,110); 
 paintbox1.canvas.MoveTo(414,81);
 paintbox1.canvas.LineTo(417,76);                                    
 paintbox1.canvas.MoveTo(364,59);
 paintbox1.canvas.LineTo(365,52);
 paintbox1.canvas.MoveTo(255,59);               
 paintbox1.canvas.LineTo(254,52);
 paintbox1.canvas.MoveTo(203,78);
 paintbox1.canvas.LineTo(201,73);
 paintbox1.canvas.MoveTo(161,110);
 paintbox1.canvas.LineTo(155,105);
 paintbox1.canvas.MoveTo(127,158);
 paintbox1.canvas.LineTo(119,154);
 paintbox1.canvas.MoveTo(106,209);
 paintbox1.canvas.LineTo(97,207);
 paintbox1.canvas.MoveTo(106,317);
 paintbox1.canvas.LineTo(97,319);
 paintbox1.canvas.MoveTo(126,368);
 paintbox1.canvas.LineTo(120,371);
 paintbox1.canvas.MoveTo(160,411);
 paintbox1.canvas.LineTo(153,418);
 paintbox1.canvas.MoveTo(414,445);
 paintbox1.canvas.LineTo(417,450);
 paintbox1.canvas.MoveTo(458,411);
 paintbox1.canvas.LineTo(462,415);
 //========================= Outer Ring Number 0,1,2,3,4,5 ....23 =============== 
 paintbox1.canvas.Font.Color := clblue;
 paintbox1.canvas.Font.Size := 10;
 paintbox1.canvas.TextOut(530,255,' 0');
 paintbox1.canvas.TextOut(524,196,' 1');
 paintbox1.canvas.TextOut(501,144,' 2');
 paintbox1.canvas.TextOut(465,97,' 3'); 
 paintbox1.canvas.TextOut(417,60,' 4');                                         
 paintbox1.canvas.TextOut(361,33,' 5');
 paintbox1.canvas.TextOut(303,26,' 6 ');
 paintbox1.canvas.TextOut(242,37,'7 ');
 paintbox1.canvas.TextOut(187,55,'8 '); 
 paintbox1.canvas.TextOut(139,91,'9 ');
 paintbox1.canvas.TextOut(95,140,'10 ');
 paintbox1.canvas.TextOut(75,195,'11 ');
 paintbox1.canvas.TextOut(68,255,' 12 ');
 paintbox1.canvas.TextOut(80,312,'13 ');                                   
 paintbox1.canvas.TextOut(101,365,'14 ');
 paintbox1.canvas.TextOut(135,417,'15 '); 
 paintbox1.canvas.TextOut(186,456,'16 ');
 paintbox1.canvas.TextOut(244,476,'17 ');
 paintbox1.canvas.TextOut(298,480,' 18 '); 
 paintbox1.canvas.TextOut(360,474,' 19');
 paintbox1.canvas.TextOut(415,453,' 20');
 paintbox1.canvas.TextOut(464,415,' 21');
 paintbox1.canvas.TextOut(497,368,' 22');
 paintbox1.canvas.TextOut(520,315,' 23'); 
end;

enter image description here

Is there a way that doesn't require me to repeat these codes so many times?


Solution

  • You don't need to hard‑code every tick and label. You can generate them dynamically with a loop and some trigonometry.

    The key is to compute the ellipse (or circle) center and radius from the TPaintBox size, then place ticks and labels relative to that. This way the drawing also automatically scales when the control is resized.

    Here's a complete example that produces a 24‑ticks dial, always centered and fitting inside the TPaintBox.

    This is for Delphi VCL:

    uses
      Math;
    
    procedure TForm1.PaintBox1Paint(Sender: TObject);
    begin
      const TickLen = 10; // inward tick length
      const TickCount = 24; // number of ticks
      const LabelGap = 20; // outward label distance
      const PaintColor = clBlue; // paint color
    
      with PaintBox1.Canvas do
      begin
        Pen.Color := PaintColor;
        Pen.Width := 1;
    
        // center of paintbox
        var cx := PaintBox1.ClientWidth / 2;
        var cy := PaintBox1.ClientHeight / 2;
    
        // choose radius so circle fits in both width and height
        var radius := Min(PaintBox1.ClientWidth, PaintBox1.ClientHeight) / 2 - LabelGap - TickLen;
    
        // draw circle (not stretched ellipse)
        Ellipse(Round(cx - radius), Round(cy - radius),
                Round(cx + radius), Round(cy + radius));
    
        Font.Color := PaintColor;
        Font.Size := 10;
    
        // adding ticks and labels
        for var I := 0 to TickCount-1 do
        begin
          var angle := DegToRad(-i * 15); // clockwise, 0 at right
    
          // outer circle point
          var xOuter := cx + radius * Cos(angle);
          var yOuter := cy + radius * Sin(angle);
    
          // inner tick point
          var xInner := cx + (radius - TickLen) * Cos(angle);
          var yInner := cy + (radius - TickLen) * Sin(angle);
    
          MoveTo(Round(xOuter), Round(yOuter));
          LineTo(Round(xInner), Round(yInner));
    
          // label position
          var tx := cx + (radius + LabelGap) * Cos(angle);
          var ty := cy + (radius + LabelGap) * Sin(angle);
          var s := I.ToString;
          var w := TextWidth(s);
          var h := TextHeight(s);
          TextOut(Round(tx - w / 2), Round(ty - h / 2), s);
        end;
      end;
    end;
    

    And this is how it looks:

    Delphi form with TPaintBox and circle drawn