You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

当Canvas.Pen.Width>1时,能否使用Canvas.Pen.Style属性?

问题解答

一、两点绘制直线的更优方案

仅需两点绘制直线时,用Canvas.MoveTo配合Canvas.LineTo比Polyline更直观,代码可读性更强,无需构造数组:

Canvas.MoveTo(P1.X, P1.Y);
Canvas.LineTo(P2.X, P2.Y);

两者绘制效果完全一致,只是写法更贴合两点连线的场景。

二、粗线条实现虚线/点线样式的解决方法

VCL的TPen在宽度大于1时无法直接使用psDash、psDot等样式,这是GDI的原生限制——宽画笔仅默认支持实线。要实现粗线条的非实线样式,可采用以下两种方案:

方案1:自定义点画图案模拟

通过GDI的点画功能,给画笔设置自定义图案来实现虚线/点线效果:

var
  StippleArray: array[0..3] of Byte; // 定义4字节的点画图案(32像素周期)
  LogBrush: TLogBrush;
begin
  // 配置图案:前16像素实,后16像素空(可按需修改数组值调整样式)
  StippleArray[0] := $FF;
  StippleArray[1] := $FF;
  StippleArray[2] := $00;
  StippleArray[3] := $00;

  Canvas.Pen.Width := 5; // 设置粗画笔宽度
  Canvas.Pen.Style := psPattern; // 切换为图案画笔样式

  // 创建点画图案的位图并关联到画笔
  LogBrush.lbStyle := BS_PATTERN;
  LogBrush.lbHatch := Integer(CreateBitmap(4, 1, 1, 8, @StippleArray));
  Canvas.Pen.Brush.Handle := CreateBrushIndirect(LogBrush);

  // 绘制直线
  Canvas.MoveTo(10, 10);
  Canvas.LineTo(300, 10);

  // 释放资源
  DeleteObject(LogBrush.lbHatch);
  DeleteObject(Canvas.Pen.Brush.Handle);
end;

方案2:手动分段绘制

通过计算直线的分段坐标,逐段绘制短线来模拟虚线,适合需要精确控制段长和间隙的场景:

procedure DrawWideDashLine(ACanvas: TCanvas; P1, P2: TPoint; LineWidth: Integer; DashLen, GapLen: Integer);
var
  DeltaX, DeltaY, TotalLen: Double;
  StepX, StepY: Double;
  CurrentPos: TPoint;
  RemainingLen: Double;
begin
  ACanvas.Pen.Width := LineWidth;
  ACanvas.Pen.Style := psSolid;

  // 计算直线总长度
  DeltaX := P2.X - P1.X;
  DeltaY := P2.Y - P1.Y;
  TotalLen := Sqrt(DeltaX * DeltaX + DeltaY * DeltaY);
  if TotalLen < 1 then Exit;

  // 计算单位长度的X、Y增量
  StepX := DeltaX / TotalLen;
  StepY := DeltaY / TotalLen;

  CurrentPos := P1;
  RemainingLen := TotalLen;

  while RemainingLen > 0 do
  begin
    // 绘制当前实线段
    var DrawLen := Min(DashLen, RemainingLen);
    var EndPos := TPoint(Round(CurrentPos.X + StepX * DrawLen), Round(CurrentPos.Y + StepY * DrawLen));
    ACanvas.MoveTo(CurrentPos.X, CurrentPos.Y);
    ACanvas.LineTo(EndPos.X, EndPos.Y);

    RemainingLen := RemainingLen - DrawLen;
    if RemainingLen <= 0 then Break;

    // 跳过间隙段
    var SkipLen := Min(GapLen, RemainingLen);
    CurrentPos := TPoint(Round(CurrentPos.X + StepX * (DrawLen + SkipLen)), Round(CurrentPos.Y + StepY * (DrawLen + SkipLen)));
    RemainingLen := RemainingLen - SkipLen;
  end;
end;

// 使用示例:绘制宽度为5,段长20、间隙10的虚线
DrawWideDashLine(Canvas, Point(10, 50), Point(300, 50), 5, 20, 10);

内容的提问来源于stack exchange,提问作者Mawg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 15:32:40