Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi DrawTextA、Courier New和Japanese地区的奇怪行为_Delphi_Winapi_Unicode_Ansi_Drawtext - Fatal编程技术网

Delphi DrawTextA、Courier New和Japanese地区的奇怪行为

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

当我将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" 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中绘制日文和中文文本他有相同的计划?这就是原因。