使用 Canvas.TextOut 有什么影响?
What are the implications of using Canvas.TextOut?
简介
我的问题来自于我这几天一直在处理的一个比较有趣的问题。我最近问了一个关于
的问题
此后我在控件方面取得了一些不错的进步,例如在中间添加分隔符以分隔名称和值行,重要的是分隔符可用于调整两列的大小。
这是我的问题开始的地方,在调整分隔线大小时显示就地编辑器导致我的控制略微变慢。因此,我进一步更改了代码,以便在未调整分隔线大小时仅显示就地编辑器。所以基本上,我使用 Canvas.TextOut
将我的值绘制为字符串,如果选择了一行,则 Inplace 编辑器如上所示。如果调整分隔线的大小,就地编辑器将隐藏,一旦调整大小操作完成,就地编辑器将再次可见。
虽然这解决了我提到的轻微减速问题,但我遇到了一个新问题,即来自就地编辑器(基本上是 TEdit)的文本与我使用 [=12 绘制的文本略有不同=]
示例 1
差异非常细微,但如果你看得足够近,你就能看到:
图 1 Canvas.TextOut
图2 DrawText
您可能需要使用屏幕放大镜才能看得更近一些,但是对于 SomeText 行,更明显的是 Some
和 Text
之间以及 [=16] 之间的间距=] 和 Text
中的 e
略有不同。
示例 2
一个稍微好一点的例子可能是将 Canvas.TextOut
和 DrawText
与就地编辑器 (TEdit) 文本进行比较:
图3比较
如您所见,这里的区别更为突出。当使用 Canvas.TextOut
时,字符串 True
清楚地显示了文本字符之间更大的间距,而 DrawText
和 inplace editor
呈现的文本完全相同。
当我使用 Canvas.TextOut
时,我在调整检查器分隔线的大小与显示和隐藏就地编辑器之间遇到了各种可怕的文本不匹配问题。如果我没有试验和尝试替代文本绘制方法,我认为我永远不会意识到其中的区别并找到解决方案。重要的是要知道我在将文本绘制到 canvas 时使用的字体设置与我为就地编辑器定义的字体完全相同。
现在我正在使用 DrawText
而不是 Canvas.TextOut
一切都与就地编辑器协同工作,这正是我想要的。
问题
我的问题是,是什么让 Canvas.TextOut
呈现文本与 DrawText
如此不同?从我的示例和处理我当前的问题,很明显 Canvas.TextOut
不会像具有相同字体设置的 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工程上运行,得到的结果如下:
图 4 测试演示
再次注意使用 Canvas.TextOut
时字符串 True
中的间距,从我的角度来看,它明显不同于 DrawText
以及 TEdit
绘制它的方式文字.
下图与图 4 相同,但放大了 400%
图 5 放大 400% 的测试演示
Text
中的 T
和 e
以及 True
中的 T
和 r
之间存在明显差异。
图 6 'Text' 这个词按照 guidelines
放大了 400%
您可以看到 T
和 e
之间的字距调整在 DrawText
中比 Canvas.TextOut
(使用 ExtTextOut
)更接近一个像素。
图 7 True
这个词按照 guidelines
放大了 700%
您可以看到 T
和 r
之间的字距在 DrawText
和就地编辑器 (TEdit) 中比 Canvas.TextOut
更近一个像素(它使用ExtTextOut
.)
我测试了几种不同的字体,以下是我的发现:
好:
Arial, Cambria, Candara, Comic Sans MS, Consolas, Courier, Courier New,
Fixedsys, Georgia, Lucida Console, Lucida Sans Unicode, Microsoft Sans
Serif, Tahoma, Terminal and Times New Roman.
差:
Calibri, Corbel, Myriad Pro, Segoe UI, Trebuchet MS and Verdana.
好的字体是那些看起来以与 DrawText
相同的方式呈现文本并且 Inpace 编辑器 (TEdit) 控件使用 Canvas.TextOut
的字体。不好的显示 Canvas.TextOut
呈现文本与其他方法略有不同。
这里可能有一些线索,虽然我不太确定,但我还是添加它以防万一。
观察到的差异是由于使用不同的 WinAPI 文本呈现函数及其行为。具体字符 kerning
In typography, kerning (less commonly mortising) is the process of
adjusting the spacing between characters in a proportional font,
usually to achieve a visually pleasing result. Kerning adjusts the
space between individual letter forms, while tracking (letter-spacing)
adjusts spacing uniformly over a range of characters.
The DrawText function draws formatted text in the specified rectangle.
It formats the text according to the specified method (expanding tabs,
justifying characters, breaking lines, and so forth).
- ExtTextOut(被
Canvas.TextOut
使用)
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
);
If the lpDx parameter is NULL, the ExtTextOut function uses the
default spacing between characters. The character-cell origins and the
contents of the array pointed to by the lpDx parameter are specified
in logical units. A character-cell origin is defined as the upper-left
corner of the character cell.
基本上 DrawText
会自动绘制格式化文本,包括调整字符间距(字距调整),而 ExtTextOut
默认情况下会使用默认字符间距(无字距调整)。如果要调整字符间距,则必须计算并提供字距调整数组 (lpDx
) 参数。
这些差异在一些字符组合中尤为明显,例如 T
和视觉上适合 T
的小写字母,或者 AV
其中一个 V
适合 A
。不同的字体也有不同的默认字距调整,这就是为什么有些字体使用这两种功能在视觉上具有相同的渲染而有些则没有。字距调整还取决于字体大小。例如,字符 AV
在 9 pt
处使用 Arial
呈现的两个函数将具有相同的输出,而 Arial
在 12 pt
将导致不同的输出。
下图中的第一行使用 ExtTextOut
无字距调整,第二行使用 DrawText
.
自动字距调整
简介
我的问题来自于我这几天一直在处理的一个比较有趣的问题。我最近问了一个关于
此后我在控件方面取得了一些不错的进步,例如在中间添加分隔符以分隔名称和值行,重要的是分隔符可用于调整两列的大小。
这是我的问题开始的地方,在调整分隔线大小时显示就地编辑器导致我的控制略微变慢。因此,我进一步更改了代码,以便在未调整分隔线大小时仅显示就地编辑器。所以基本上,我使用 Canvas.TextOut
将我的值绘制为字符串,如果选择了一行,则 Inplace 编辑器如上所示。如果调整分隔线的大小,就地编辑器将隐藏,一旦调整大小操作完成,就地编辑器将再次可见。
虽然这解决了我提到的轻微减速问题,但我遇到了一个新问题,即来自就地编辑器(基本上是 TEdit)的文本与我使用 [=12 绘制的文本略有不同=]
示例 1
差异非常细微,但如果你看得足够近,你就能看到:
图 1 Canvas.TextOut
图2 DrawText
您可能需要使用屏幕放大镜才能看得更近一些,但是对于 SomeText 行,更明显的是 Some
和 Text
之间以及 [=16] 之间的间距=] 和 Text
中的 e
略有不同。
示例 2
一个稍微好一点的例子可能是将 Canvas.TextOut
和 DrawText
与就地编辑器 (TEdit) 文本进行比较:
图3比较
如您所见,这里的区别更为突出。当使用 Canvas.TextOut
时,字符串 True
清楚地显示了文本字符之间更大的间距,而 DrawText
和 inplace editor
呈现的文本完全相同。
当我使用 Canvas.TextOut
时,我在调整检查器分隔线的大小与显示和隐藏就地编辑器之间遇到了各种可怕的文本不匹配问题。如果我没有试验和尝试替代文本绘制方法,我认为我永远不会意识到其中的区别并找到解决方案。重要的是要知道我在将文本绘制到 canvas 时使用的字体设置与我为就地编辑器定义的字体完全相同。
现在我正在使用 DrawText
而不是 Canvas.TextOut
一切都与就地编辑器协同工作,这正是我想要的。
问题
我的问题是,是什么让 Canvas.TextOut
呈现文本与 DrawText
如此不同?从我的示例和处理我当前的问题,很明显 Canvas.TextOut
不会像具有相同字体设置的 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工程上运行,得到的结果如下:
图 4 测试演示
再次注意使用 Canvas.TextOut
时字符串 True
中的间距,从我的角度来看,它明显不同于 DrawText
以及 TEdit
绘制它的方式文字.
下图与图 4 相同,但放大了 400%
图 5 放大 400% 的测试演示
Text
中的 T
和 e
以及 True
中的 T
和 r
之间存在明显差异。
图 6 'Text' 这个词按照 guidelines
放大了 400%您可以看到 T
和 e
之间的字距调整在 DrawText
中比 Canvas.TextOut
(使用 ExtTextOut
)更接近一个像素。
图 7 True
这个词按照 guidelines
您可以看到 T
和 r
之间的字距在 DrawText
和就地编辑器 (TEdit) 中比 Canvas.TextOut
更近一个像素(它使用ExtTextOut
.)
我测试了几种不同的字体,以下是我的发现:
好:
Arial, Cambria, Candara, Comic Sans MS, Consolas, Courier, Courier New, Fixedsys, Georgia, Lucida Console, Lucida Sans Unicode, Microsoft Sans Serif, Tahoma, Terminal and Times New Roman.
差:
Calibri, Corbel, Myriad Pro, Segoe UI, Trebuchet MS and Verdana.
好的字体是那些看起来以与 DrawText
相同的方式呈现文本并且 Inpace 编辑器 (TEdit) 控件使用 Canvas.TextOut
的字体。不好的显示 Canvas.TextOut
呈现文本与其他方法略有不同。
这里可能有一些线索,虽然我不太确定,但我还是添加它以防万一。
观察到的差异是由于使用不同的 WinAPI 文本呈现函数及其行为。具体字符 kerning
In typography, kerning (less commonly mortising) is the process of adjusting the spacing between characters in a proportional font, usually to achieve a visually pleasing result. Kerning adjusts the space between individual letter forms, while tracking (letter-spacing) adjusts spacing uniformly over a range of characters.
The DrawText function draws formatted text in the specified rectangle. It formats the text according to the specified method (expanding tabs, justifying characters, breaking lines, and so forth).
- ExtTextOut(被
Canvas.TextOut
使用)
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
);
If the lpDx parameter is NULL, the ExtTextOut function uses the default spacing between characters. The character-cell origins and the contents of the array pointed to by the lpDx parameter are specified in logical units. A character-cell origin is defined as the upper-left corner of the character cell.
基本上 DrawText
会自动绘制格式化文本,包括调整字符间距(字距调整),而 ExtTextOut
默认情况下会使用默认字符间距(无字距调整)。如果要调整字符间距,则必须计算并提供字距调整数组 (lpDx
) 参数。
这些差异在一些字符组合中尤为明显,例如 T
和视觉上适合 T
的小写字母,或者 AV
其中一个 V
适合 A
。不同的字体也有不同的默认字距调整,这就是为什么有些字体使用这两种功能在视觉上具有相同的渲染而有些则没有。字距调整还取决于字体大小。例如,字符 AV
在 9 pt
处使用 Arial
呈现的两个函数将具有相同的输出,而 Arial
在 12 pt
将导致不同的输出。
下图中的第一行使用 ExtTextOut
无字距调整,第二行使用 DrawText
.