【发布时间】:2015-11-05 06:32:20
【问题描述】:
简介
我的问题来自过去几天我一直在处理的一个相当有趣的问题。我最近问了一个关于Writing a custom property inspector - How to handle inplace editor focus when validating values?的问题
此后,我在控件方面取得了一些不错的进展,例如在中间添加一个分隔线来分隔名称和值行,重要的是,分隔线可用于调整两列的大小。
这是我的问题开始的地方,在调整分隔线大小的同时显示就地编辑器导致我的控制稍微变慢。因此,我进一步更改了代码,仅在未调整分隔线大小时才显示就地编辑器。所以本质上,我使用Canvas.TextOut 将我的值绘制为字符串,如果选择了一行,则 Inplace 编辑器如上所示。如果调整分隔线的大小,就地编辑器将隐藏,一旦调整大小操作完成,就地编辑器将再次可见。
虽然这解决了我提到的轻微减速问题,但我遇到了一个新问题,即来自就地编辑器(基本上是 TEdit)的文本与我使用 Canvas.TextOut 绘制的文本略有不同
示例 1
差异非常微妙,但如果你看得足够近,你就能看到它:
图 1 Canvas.TextOut
图 2 DrawText
您可能需要使用屏幕放大镜才能看得更近,但在 SomeText 行中,Some 和 Text 之间以及 T 和 e 之间的间距更明显987654342@ 略有不同。
示例 2
一个更好的例子可能是将Canvas.TextOut 和DrawText 与就地编辑器(TEdit)文本进行比较:
图3比较
如您所见,这里的区别更为突出。使用Canvas.TextOut 时,字符串True 清楚地显示文本字符之间的间距要大得多,而DrawText 和inplace editor 呈现的文本完全相同。
当我使用Canvas.TextOut 时,我在调整检查器分隔符的大小以及显示和隐藏就地编辑器之间遇到了各种可怕的文本不匹配。如果我没有尝试和尝试替代文本绘制方法,我认为我永远不会意识到差异并找到解决方案。重要的是要知道,在将文本绘制到画布时,我使用的字体设置与我为就地编辑器定义的字体完全相同。
现在我使用的是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 文字“文本”放大 400% 并带有指南
您可以看到T 和e 之间的字距与DrawText 相比比Canvas.TextOut(使用ExtTextOut)更近一个像素。
图 7 True 这个词在指引下放大了 700%
您可以看到T 和r 之间的字距调整比Canvas.TextOut(使用ExtTextOut)更接近DrawText 和就地编辑器(TEdit)。
我测试了几种不同的字体,以下是我的发现:
好:
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。
好的字体是那些呈现文本的方式与DrawText 和Inpace Editor (TEdit) 控件使用Canvas.TextOut 的方式相同的字体。坏的表明Canvas.TextOut 呈现文本与其他方法略有不同。
这里可能有一些线索,虽然我不太确定,但我还是添加它以防万一。
【问题讨论】:
-
开始一个新的 VCL 项目,在表单的 OnPaint 处理程序中放置 thre 行代码,这会重复问题。可以复制吗?我不能用W7。如果你也不能,那么没有案例就没有问题。
-
TextOut内部使用ExtTextOut。 -
@SertacAkyuz 测试演示已添加,我使用的是 Windows 10。
-
我隐约记得过去曾注意到这种差异。就好像这两个函数在内部使用了稍微不同的字距调整算法。不过,可能是不同渲染标志的情况。看看这里发现了什么会很有趣。
-
无论确定的答案是什么,这都是个好问题。
标签: delphi delphi-xe7