使用Canvas.TextOut有什么含义?

时间:2015-08-12 14:55:47

标签: delphi delphi-xe7

简介

我的问题来自于过去几天我一直在处理的一个相当有趣的问题。我最近问了一个关于Writing a custom property inspector - How to handle inplace editor focus when validating values?

的问题

我已经在我的控件上取得了一些不错的进展,比如在中间添加一个分隔符来分隔Name和Value行,重要的是分隔符可以用来调整两列的大小。

这是我的问题开始的地方,让inplace编辑器可见,同时调整分隔符的大小导致我的控制稍微减慢。所以我进一步改变了代码,只显示了inplace编辑器,如果没有调整分隔符的大小。基本上,我使用Canvas.TextOut将我的值绘制为字符串,如果选择了一行,则上面显示了Inplace编辑器。如果已调整分隔符大小,则inplace编辑器将变为隐藏状态,一旦调整大小操作完成,就位编辑器将再次可见。

虽然这解决了我提到的轻微减速问题,但我遇到了一个新问题,因为来自内部编辑器(基本上是TEdit)的文本与我使用Canvas.TextOut绘制的文本略有不同

示例1

差异非常微妙但如果你看得足够近,你可以看到它:

图1 Canvas.TextOut

enter image description here

图2 DrawText

您可能需要使用屏幕放大镜来更贴近,但使用SomeText行时,SomeText之间以及T之间的间距会更明显e中的Text略有不同。

示例2

稍微好一点的例子可能是在Canvas.TextOutDrawText之间与就地编辑器(TEdit)文本进行比较:

enter image description here

图3比较

正如您所看到的,这里的区别更加突出。使用True时,字符串Canvas.TextOut清楚地显示文本字符之间的间距要大得多,其中DrawTextinplace editor呈现的文字完全相同。

当我使用Canvas.TextOut时,在调整检查器分隔符的大小以及显示和隐藏原位编辑器之间,我遇到了各种可怕的文本不匹配。如果我没有尝试并尝试替代的文字绘图方法,我不认为我会意识到差异并找到了解决方案。重要的是要知道我在将文本绘制到画布时使用完全相同的字体设置作为我为内置编辑器定义的字体。

现在我正在使用DrawText而不是Canvas.TextOut,所有内容都与内置编辑器一致,并且正是我想要的。

问题

我的问题是什么使Canvas.TextOut呈现文字的方式与DrawText不同?从我的示例和处理我当前的问题,很明显Canvas.TextOut不会以与具有相同Font设置的TEdit相同的方式呈现文本,但DrawText确实呈现文本看似正确方式。

这让我对Canvas.TextOut的使用提出质疑,如果它无法正确呈现文字,我应该总是使用DrawText吗?

测试演示

您可以使用以下代码自行测试:

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormPaint(Sender: TObject);
  private
    FFont: TFont;
    FRect: TRect;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FFont       := TFont.Create;
  FFont.Color := clNavy;
  FFont.Name  := 'Segoe UI';
  FFont.Size  := 9;
  FFont.Style := [];
  FRect       := Rect(10, 30, 100, 100);

  Canvas.Font.Assign(FFont);
  Edit1.Font.Assign(FFont);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FFont.Free;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin 
  Canvas.TextOut(10, 10, 'Canvas.TextOut: [True]');
  DrawText(Canvas.Handle, PChar('DrawText: [True]'), Length('DrawText: [True]'), FRect, DT_LEFT);
end;

上面运行一个全新的VCL项目,我得到的结果如下:

enter image description here

图4测试演示

再次注意使用True时字符串Canvas.TextOut中的间距,从我的结尾看,它明显不同于DrawText以及TEdit绘制文字的方式。

以下是与图4相同的图像,但放大率为400%

enter image description here

图5测试演示缩放为400%

T中的eText以及T中的rTrue之间存在明显的差异。

enter image description here

图6单词' Text'使用指南放大了400%

您可以看到Te之间的字距调整与DrawText的距离比使用Canvas.TextOut ExtTextOut的{​​{1}}更接近一个像素。)

enter image description here

图7单词True以指南放大了700%

您可以看到Tr之间的字距调整与DrawText和Inplace Editor(TEdit)比使用Canvas.TextOut(使用{{}更接近一个像素。 1}}。)

我测试了几种不同的字体,这是我的发现:

好:

  

Arial,Cambria,Candara,Comic Sans MS,Consolas,Courier,Courier New,   Fixedsys,Georgia,Lucida Console,Lucida Sans Unicode,Microsoft Sans   Serif,Tahoma,Terminal和Times New Roman。

为:

  

Calibri,Corbel,Myriad Pro,Segoe UI,Trebuchet MS和Verdana。

好的字体看起来像ExtTextOut一样呈现文本,而Inpace Editor(TEdit)控件使用DrawText。坏的表明Canvas.TextOut呈现的文本与其他方法略有不同。

虽然我不太确定,但这里可能有一些线索,但无论如何我都会添加它以防万一。

1 个答案:

答案 0 :(得分:7)

观察到的差异是由于使用了不同的WinAPI文本呈现函数及其行为。特别是字符kerning

  

在排版中,字距调整(不太常见的榫眼)就是这个过程   调整比例字体中字符之间的间距,   通常是为了获得视觉上令人愉悦的结果。 Kerning调整了   单个字母表格之间的空格,同时跟踪(字母间距)   在一系列字符上均匀调整间距。

  1. DrawText
  2.   

    DrawText函数在指定的矩形中绘制格式化文本。   它根据指定的方法格式化文本(扩展选项卡,   证明字符,断线等等。

    1. ExtTextOut(由Canvas.TextOut使用)
    2. ExtTextOut声明:

      BOOL ExtTextOut(
        _In_       HDC     hdc,
        _In_       int     X,
        _In_       int     Y,
        _In_       UINT    fuOptions,
        _In_ const RECT    *lprc,
        _In_       LPCTSTR lpString,
        _In_       UINT    cbCount,
        _In_ const INT     *lpDx
      );
      
        

      如果lpDx参数为NULL,则ExtTextOut函数使用   字符之间的默认间距。角色细胞起源和   指定了lpDx参数指向的数组的内容   以逻辑单位。字符单元格原点定义为左上角   角色单元格的一角。

      基本上DrawText会自动绘制格式化文本,包括调整字符间距(字距调整),而ExtTextOut默认情况下会使用字符间的默认间距(no-kerning)。如果要调整字符间距,则必须计算并提供字距调整数组(lpDx)参数。

      这些差异特别适用于某些字符组合,例如T和视觉上适合T的小写字母,或AV其中V适合A }。不同的字体也有不同的默认字距,这就是为什么有些字体使用两种功能在视觉上相同的渲染而有些不是。字距也取决于字体大小。例如,在AV处使用Arial呈现的字符9 pt将同时具有两个函数的输出,而Arial处的12 pt将导致不同的输出。

      以下图片中的第一行使用ExtTextOut进行无字距调整,第二行使用DrawText进行自动字距调整。

      enter image description here