Delphi DrawTextA、Courier New和Japanese地区的奇怪行为
当我将DrawTextA与Courier的日语新字体结合使用时,我发现了一些奇怪的行为。请考虑下面的Delphi XE2代码:Delphi DrawTextA、Courier New和Japanese地区的奇怪行为,delphi,winapi,unicode,ansi,drawtext,Delphi,Winapi,Unicode,Ansi,Drawtext,当我将DrawTextA与Courier的日语新字体结合使用时,我发现了一些奇怪的行为。请考虑下面的Delphi XE2代码: procedure PaintTexts(aPaintBox: TPaintBox; aCharset: Byte); var A: AnsiString; S: string; R: TRect; begin aPaintBox.Font.Charset := aCharset; A := '[DrawTextA] The word "Japan
procedure PaintTexts(aPaintBox: TPaintBox; aCharset: Byte);
var
A: AnsiString;
S: string;
R: TRect;
begin
aPaintBox.Font.Charset := aCharset;
A := '[DrawTextA] The word "Japan" in Japanese: 日本';
R := Rect(0, 0, aPaintBox.Width, aPaintBox.Height);
DrawTextA(aPaintBox.Canvas.Handle, PAnsiChar(A), Length(A), R, 0);
S := '[DrawTextW] The word "Japan" in Japanese: 日本';
R := Rect(0, 20, aPaintBox.Width, aPaintBox.Height);
DrawTextW(aPaintBox.Canvas.Handle, PWideChar(S), Length(S), R, 0);
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
PaintTexts(PaintBox1, DEFAULT_CHARSET);
end;
procedure TForm1.PaintBox2Paint(Sender: TObject);
begin
PaintTexts(PaintBox2, SHIFTJIS_CHARSET);
end;
在此代码中,Form1包含两个油漆盒(油漆盒1和油漆盒2)。Form1的字体设置为Courier New,两个颜料盒已将ParentFont设置为True。Windows的非Unicode区域设置为日语(日本),因此它使用代码页932
结果如下所示:
第一个paintbox显示了DrawTextA和DrawTextW调用的输出,该调用具有Charset属性Charset_DEFAULT。这是字体字符集属性的默认值。注意,日语单词日本 传递给DrawTextA时未正确显示。然而,DrawTextW完美地绘制了它
第二个paintbox显示相同的文本,但仅将Charset属性更改为SHIFTJIS_Charset。现在两个调用都显示正确的日语字符。但字体已更改为可变宽度字体
当我将Form1的字体更改为Tahoma时,DrawTextA和DrawTextW都显示相同的正确文本
当我的非Unicode语言环境设置为日语,字体设置为Courier New时,有人知道为什么DrawTextA的行为与DrawTextW不同吗?
我一直认为,Windows API的Ansi版本和Wide版本之间的唯一区别在于Ansi版本处理Unicode与Unicode之间的转换
我曾尝试将其与Windows XP和Windows 7以及Delphi 7和Delphi XE2结合使用。所有组合都表现出相同的行为
更新:
在大卫·赫弗南发布了他的答案后,我开始阅读。我在那里找到了,而且。
DrawTextA
不会将文本转换为Unicode。相反,所选字体的字符集用于解释提供的文本。这确实比典型的A
和W
后缀API函数要复杂一些
字体字符集的使用允许非Unicode程序以多个字符集显示文本。对于Unicode程序,这完全不是问题,因为Unicode可以对所有字符进行编码
根据迈克尔·卡普兰的说法,DEFAULT\u FONTSET
不应使用。他说:
不要使用默认的字符集。这是邪恶的
如果需要指定字符集,应执行以下操作:
GetACP
以获取激活的代码页TranslateCharsetInfo
传递代码页并指定TCI\u SRCCODEPAGE
标志function CharsetFromCP(CP: UINT): UINT;
var
csi: TCharsetInfo;
begin
Win32Check(TranslateCharsetInfo(CP, csi, TCI_SRCCODEPAGE));
Result := csi.ciCharset;
end;
然后你可以写:
aPaintBox.Font.Charset := CharsetFromCP(GetACP);
当然,如果您知道文本是日语,那么您可以直接编写
SHIFTJIS\u字符集
。更明显的是,您可以简单地使用Unicode API并避免所有这些废话。Courier新字体是否有用于SHIFTJIS_CHARSET
CHARSET的字符?根据字符映射,它没有。我在Delphi 7应用程序的TLabel中注意到了这种行为。用Delphi XE2编写的另一个应用程序没有显示此问题,尽管它使用相同的代码结构。经过一些调查,我发现唯一的区别是调用DrawTextW(Delphi XE2)而不是DrawTextA(Delphi 7)。为了简单起见,我将问题简化为问题中使用的示例。调试器显示这两个日文字符由4个字节编码:#$93、#$FA、#$96、#$7B。正如您在上所看到的,这四个字节对两个日语字符进行编码(日本).谢谢你的评论,这些信息真的很有用。但实际上,它并没有真正回答我的问题。我一直认为Windows API的A版本只做了一些ANSI Unicode(反之亦然)转换。鉴于此,我认为DrawTextA只需将字符串转换为Unicode,然后调用DrawTextW。我正在处理的项目是Delphi 7应用程序,我必须添加对不同语言(如日语、汉语、俄语)的支持。不幸的是,我不能简单地将其移植到Delphi XE2应用程序中。事实显然并非如此。您可以从程序中看到这一点。字体的Charset
属性决定文本如何发出。我将在答案中添加一些文本以得出结论。我完全明白Charset属性决定文本如何发出使用DrawTextA时呈现。但当我使用DrawTextW时,无论字符集属性如何,它始终呈现正确的日语字符。但它确实会影响所选字体(它将固定宽度字体替换为非固定宽度字体)当您调用<代码> DrawTextW < /Code >时,您正在传递Unicode字符。当您调用<代码> DrawTextA < /Code >时,您需要指定编码。基本上字符集就是为了这个目的。如果没有字符集,那么就没有办法使用活动代码页之外的字符来绘制文本。请考虑如何使用<代码> DrawTextA < /Code >。在同一个程序中绘制日文和中文文本。同样,假设没有字符集,DrawTextA
使用活动代码页简单地调用MultiByteToWideChar
,并将其传递给DrawTextW
。如果是这样,您将如何使用DrawTextA
在t中绘制日文和中文文本他有相同的计划?这就是原因。