CodeTyphon实现跨平台绘制文字

本文针对 CodeTyphon 6.30 及后续版本。

最近依然坚持在使用 CodeTyphon 做跨平台的开发,涉及到绘画的部分,发现坑不少,特此写一篇来填坑。

首先是 Graphics 单元,由于各平台实现机制不同,并且都需要大量的初始化工作,因此不能直接 uses 就完事,必须在 ppr 文件内进行对 Interfaces 的引用。如果是 Terminal 应用,还需要手动引用 adLCL 库。

针对 adLCL 这个库,原本的名称为 LCL 或 bsLCL,视不同的版本拥有不同的名称,但是本质上是同一个东西,在 6.30 及后续版本,该库的名称被改为 adLCL

随后就是要进行绘图了,这部分其实非常的坑,在各个平台上,相同的绘图的函数将产生不同的作用。举个栗子,在图片上添加自动换行的文字:

with Canvas do begin
    Pen.Color := clBlack;
    Brush.Style := bsClear;
    TextStyle.WordBreak := True;
    TextStyle.SingleLine := False;
    TextRect(rect, x, y, str);
end;

这段代码在 Windows 上工作完善,在 Linux 上将报出 GLib-GObject-CRITICAL 的异常,并最终引起闪退(神奇的是有的时候可以正常工作),而在 Mac 上这段代码不能实现自动换行!

好了,这样不稳定的代码还是放弃吧,我们应当能有更好的办法来解决这问题。首先可以确定的是,TextOut 函数在任何平台都可以正常工作,因此我们努力的方向也应当是将 TextRect 改成 TextOut,这其中需要做一些运算。

首先把要绘制的文字拆成行,注意在拆的时候需要使用 UTF8 编码,以避免不必要的字符串截断问题:

function text2Lines(acanvas: TCanvas; astr: string; arect: TRect): TStringArray;
var
  len: Integer;
  w: Integer;
  lines: Integer;
  i: Integer;
  j: Integer;
  atmp: string;
  idx: Integer;
begin
  len := UTF8Length(astr);
  w := acanvas.TextWidth(astr);
  lines:= w div (rect.Right - rect.Left);
  if (w mod (rect.Right - rect.Left) <> 0) then lines += 1;
  SetLength(Result, lines);
  idx := 0;
  for i:= 0 to lines - 1 do begin
    atmp:= '';
    for j := idx to len - 1 do begin
      atmp += UTF8Copy(astr, j, 1);
      if (acanvas.TextWidth(atmp) > awidth) then begin
        UTF8Delete(atmp, UTF8Length(atmp) , 1);
        Result[i] := atmp;
        idx := j;
        Break;
      end;
    end;
  end;
  if (idx < len) then begin
    if (Result[lines - 1].Trim = '') then begin
      Result[lines - 1] := UTF8Copy(astr, idx, len);
    end else begin
      SetLength(Result, lines + 1);
      Result[lines] := UTF8Copy(astr, idx, len);
    end;
  end;
end;

然后用 TextOut 画出来就行了,这里需要多加一个行高的变量:

with Canvas do begin
    Pen.Color := clBlack;
    Brush.Style := bsClear:
    lines := text2Lines(Canvas, str, rect);
    for i:= 0 to Length(lines) - 1 do begin
      TextOut(x, y + lineHeight * i, lines[i]);
    end;
  end;

到此,在所有的平台上得到的效果均是相同的了。以上问题已在 CodeTyphon 论坛予以反馈,希望能得到官方的重视,不过说到底,还是自己动手解决来得快,不能懒啊。

这个修改同样可以被编译到 Android 以及 iOS 平台,具体的编译方法就不细说了,我懒(无意中打了脸)。

你可能感兴趣的:(CodeTyphon实现跨平台绘制文字)