本文针对 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 平台,具体的编译方法就不细说了,我懒(无意中打了脸)。