如何优化带360度刻度椭圆的绘制代码?避免重复调用MoveTo和LineTo
优化椭圆刻度绘制的重复代码问题
我在窗体的PaintBox上绘制了带360度刻度的椭圆,但目前需要多次重复调用MoveTo和LineTo来绘制刻度,同时手动定位每个数字的位置,代码冗余严重。以下是当前的PaintBox1Paint事件处理代码:
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;
请问是否有避免大量重复代码的优化方法?
优化方案
当然可以通过三角函数计算位置+循环遍历的方式彻底消除重复代码,核心思路是利用椭圆的参数方程,计算每个刻度和数字的坐标,然后批量绘制。
步骤1:提取椭圆核心参数
先算出椭圆的中心坐标、长半轴和短半轴:
- 原椭圆边界为
Ellipse(98,51,520,473),因此:- 中心X:
(98 + 520) / 2 = 309 - 中心Y:
(51 + 473) / 2 = 262 - 长半轴(水平方向):
(520 - 98) / 2 = 211 - 短半轴(垂直方向):
(473 - 51) / 2 = 211(注:你这里实际是正圆,不过代码兼容椭圆场景)
- 中心X:
步骤2:循环绘制刻度与数字
利用Sin和Cos函数计算每个角度对应的坐标,循环处理24个刻度(对应15度间隔):
procedure PaintBox1Paint(Sender: TObject); const // 椭圆参数 CenterX = 309; CenterY = 262; RadiusX = 211; RadiusY = 211; // 刻度配置 TickCount = 24; TickAngleStep = 360 / TickCount; // 每个刻度间隔15度 TickLength = 7; // 刻度线长度 // 数字偏移量(让数字在椭圆外侧) TextOffset = 15; var I: Integer; Angle: Double; Radian: Double; X1, Y1, X2, Y2: Integer; TextX, TextY: Integer; TextStr: string; begin PaintBox1.Canvas.Pen.Color := clBlue; PaintBox1.Canvas.Pen.Width := 1; // 绘制椭圆 PaintBox1.Canvas.Ellipse(98, 51, 520, 473); // 设置字体 PaintBox1.Canvas.Font.Color := clBlue; PaintBox1.Canvas.Font.Size := 10; // 循环绘制所有刻度和数字 for I := 0 to TickCount - 1 do begin // 将角度转换为弧度(Delphi三角函数使用弧度) Angle := I * TickAngleStep; Radian := DegToRad(Angle); // 计算椭圆上的点(刻度内侧端点) X1 := Round(CenterX + RadiusX * Cos(Radian)); Y1 := Round(CenterY + RadiusY * Sin(Radian)); // 计算刻度外侧端点 X2 := Round(CenterX + (RadiusX + TickLength) * Cos(Radian)); Y2 := Round(CenterY + (RadiusY + TickLength) * Sin(Radian)); // 绘制刻度线 PaintBox1.Canvas.MoveTo(X1, Y1); PaintBox1.Canvas.LineTo(X2, Y2); // 计算数字位置(在刻度外侧更远处) TextX := Round(CenterX + (RadiusX + TextOffset) * Cos(Radian)); TextY := Round(CenterY + (RadiusY + TextOffset) * Sin(Radian)); TextStr := IntToStr(I); // 根据角度微调数字位置,避免偏移过多 case I of 0: PaintBox1.Canvas.TextOut(TextX + 5, TextY - 5, TextStr); 6: PaintBox1.Canvas.TextOut(TextX - 5, TextY - 10, TextStr); 12: PaintBox1.Canvas.TextOut(TextX - 10, TextY - 5, TextStr); 18: PaintBox1.Canvas.TextOut(TextX - 5, TextY, TextStr); else PaintBox1.Canvas.TextOut(TextX, TextY, TextStr); end; end; end;
优化后的优势
- 代码量大幅减少,逻辑清晰易维护
- 可通过修改常量快速调整刻度数量、间隔、长度
- 自动适配椭圆参数,后续椭圆大小变化时只需更新核心参数
- 避免手动计算坐标的繁琐与出错概率
内容的提问来源于stack exchange,提问作者Ebrahim
相关产品推荐
相关产品推荐

