(Delphi FMX) 如何使用 Canvas.FillText 显示在椭圆的中间?

(Delphi FMX) How do I use Canvas.FillText to show up in the middle of an Ellipse?

我想将椭圆中间的数字显示为 canvas 上绘制的文本。坐标将存储(对于椭圆)在数据库内部,文本值将存储在数据库的另一部分。

到目前为止我所做的是我一直在使用来自 FMXExpress (Github) 的演示项目 (DrawApp),其中我将一些程序从私有更改为 Public。这些程序包括 StartDrawing(startP:TPointF)、EndDrawing(startP:TPointF)、DoDraw() 这样我就可以从外部使用这些函数 Unit/Object。 object 与 MouseUp/MouseDown 配合使用这些函数,以及包括 fDrawing 在内的一些属性来区分绘图是否正在进行,以及正在使用什么工具 (fdEllipse)。

我的主窗体在 FormCreate 中使用以下代码来初始创建 fdrawbox := TMyPaintBox.Create(Rectangle1); Rectangle1 位于图像的顶部,它代表一个网格以显示 body 部分,并且能够在图像的顶部绘制圆圈。我发现创建文本或椭圆并不难,但是为了创建多个带有标识符的圆圈以区分圆圈,正如我所提到的,我想要一个数字来显示哪个圆圈是哪个。甚至在未来,我可能想要更改颜色以显示要专注于哪个圆圈。

demonstration for mypaintbox http://www.abatepain.com/abate/OHlbF.jpg

因此以下代码 (Delphi FMX) 显示了通过使用 TRectangle 作为其 parent.

创建一个 drawapp
with fdrawbox do begin
  Parent := Rectangle1;
  Visible := True;
  ForegroundColor := TAlphaColor($FF000000); //
  BackgroundColor := TAlphaColor([=12=]000000); //

  FuncDraw := TFunctionDraw.fdEllipse; //fdrawbox.fDrawing := True;
  StartDrawing(PointF(100, 100));
  EndDrawing(PointF(200, 200));
  FuncDraw := TFunctionDraw.fdNone;

  OnPaint := PaintBox1Paint;
end;

圆是使用最后几行创建的,但是为了使用 FillText,我需要使用我创建的 OnPaint 函数,代码看起来像这样。我相信 DrawApp 在内部处理 OnPaint 函数,但它如何处理它仍然是未知的。但打印 "Hello Text!!"

的必要性永远不会降低
procedure TMainForm.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  with Canvas do begin
    BeginScene();
    //Clear(cbbg.Color);
    Font.Style := [];
    Font.Size := 12;
    Fill.Color := TAlphaColors.Red;
    FillText(TRectF.Create(0, 0, 300, 295), 'Hello Text!!', false, 100, [], TTextAlign.Center, TTextAlign.Center); //TFillTextFlag.RightToLeft
    EndScene;
  end;
  Application.ProcessMessages;
end;

有人可以举例说明如何处理这个问题(可能在单个函数内),我可以在其中打印多个圆圈并在其后添加相关文本吗?我相信对于前面的示例,我可以自己完成,但是我必须手动输入 PointF(用于圆)和 TRectF 用于文本,并且它们都使用不同的值作为坐标。

如您所知,TMyPaintBox class 不支持文本呈现,也不支持文本输出中常用的属性,如字体或颜色等。但您可以通过定义字段自行添加这些属性在私有部分和 get/set public 部分中的值的属性。

在下文中,我假设添加的字段 ftextoutffontsizeffontcolor 具有相应的属性 TextOut FontSizeFontColor

要添加以与绘制其他元素类型类似的方式呈现文本的功能,请将 fdText 作为新枚举添加到 TFunctionDraw

  TFunctionDraw=(fdNone,fdPen,fdLine,fdRectangle,fdEllipse,fdFillBgr,fdBitmapStamp,fdPolyLine, fdText);

然后在 TMyPaintBox.DoDraw 中向 case ffdraw of 添加一个新的大小写选项,例如:

with vCanvas do
begin
BeginScene();
case ffdraw of 
  //
  // other TFunctionDraw enums
  //
  TFunctionDraw.fdText: begin
    {Canvas.}Font.Size := ffonsize; // new field
    {Canvas.}Fill.Color := ffontcolor; // new field 
    {Canvas.}FillText(r, TextOut, False, 1, [],
      TTextAlign.Center, TTextAlign.Center);
  end;
end;

编辑:

TFunctionDraw.fdText 中对 Canvas 的引用是多余的。删除注释掉的引用。要使用的 canvas 已在 with 语句中定义(添加到要显示的代码中)。哦,我讨厌那些 withs!

同样值得注意的是,如果你只想显示带有文本的圆圈,而不是让用户在 canvas 上绘制,你可以使用自己制作的组件来实现它更简单.

另外,不要直接调用DoDraw。它由 Paint 调用,只要 fdrawbox 无效就会被触发。因此,当您想要强制更新时,请改为调用 invalidate

编辑结束

然后您就可以像任何其他元素绘制一样实现文本渲染(使用您的代码模板):

with fdrawbox do begin
  Parent := Rectangle1;
  Visible := True;
  ForegroundColor := TAlphaColor($FF000000); //
  BackgroundColor := TAlphaColor([=12=]000000); //

  FuncDraw := TFunctionDraw.fdEllipse; //fdrawbox.fDrawing := True;
  StartDrawing(PointF(100, 100));
  EndDrawing(PointF(200, 200));

  FuncDraw := TFunctionDraw.fdText;
  FontSize := 12; // set new property
  FontColor := TAlphaColorRec.Red; // set new property
  TextOut := 'Hello text!';
  StartDrawing(PointF(100, 100));
  EndDrawing(PointF(200, 200));

  FuncDraw := TFunctionDraw.fdNone;

  invalidate;
  // OnPaint := PaintBox1Paint; // no need for this
end;