将DrawTextA与带有日语语言环境的Courier New-font结合使用时,我发现了一些奇怪的行为。请考虑以下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" 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包含两个绘图框(PaintBox1和PaintBox2)。 Form1的字体设置为Courier New,两个绘图框将ParentFont设置为True。 Windows的非Unicode区域设置设置为日语(日本),因此它使用代码页932。
结果如下:
第一个paintbox显示DrawTextA的输出和带有Charset属性CHARSET_DEFAULT的DrawTextW调用。这是字体的charset属性的默认值。请注意,传递给DrawTextA时,日语单词日本未正确显示。但是, DrawTextW完美地绘制它。
第二个paintbox显示相同的文本,但只有Charset属性更改为SHIFTJIS_CHARSET。现在两个调用都显示正确的日文字符。但字体已更改为可变宽度字体!
当我将Form1的字体更改为Tahoma时,DrawTextA和DrawTextW都显示相同的正确文本。
当我的非Unicode语言环境设置为日语并且我的字体设置为Courier New时,有没有人知道为什么DrawTextA的行为与DrawTextW不同?
我一直认为Windows API的Ansi-和Wide版本之间的唯一区别是Ansi版本处理了与Unicode的转换。
我已经尝试过与Windows XP和Windows 7,Delphi 7和Delphi XE2结合使用。所有组合都表现出相同的行为。
更新 David Heffernan发表回答后,我开始阅读Micheal Kaplan's blog。在那里,我找到了a similar topic和more information about this topic。
答案 0 :(得分:1)
DrawTextA
不会将文本转换为Unicode。而是使用所选字体的字符集来解释所提供的文本。这确实比典型的A
和W
后缀API函数更复杂一些。
使用字体字符集允许非Unicode程序显示多个字符集中的文本。对于Unicode程序,这是一个完全没有问题,因为Unicode可以编码所有字符。
根据this forum thread中的Michael Kaplan,DEFAULT_FONTSET
不应使用GetACP
。他说:
根本不要使用DEFAULT_CHARSET。这很邪恶。
如果需要指定字符集,则应执行以下操作:
TranslateCharsetInfo
以获取有效代码页。TCI_SRCCODEPAGE
传递代码页并指定function CharsetFromCP(CP: UINT): UINT;
var
csi: TCharsetInfo;
begin
Win32Check(TranslateCharsetInfo(CP, csi, TCI_SRCCODEPAGE));
Result := csi.ciCharset;
end;
标志。返回的charset信息信息是用于活动代码页的相应字符集。把它包起来:
aPaintBox.Font.Charset := CharsetFromCP(GetACP);
然后你可以写:
SHIFTJIS_CHARSET
当然,如果你知道文字是日文,那么你可以直接写{{1}}。更明显的是,您可以简单地使用Unicode API并避免所有这些废话。