【问题标题】:Delphi: TRichEdit Text in non-default non-Unicode system language as String (ANSI)Delphi:以非默认非 Unicode 系统语言作为字符串 (ANSI) 的 TRichEdit 文本
【发布时间】:2013-04-01 10:31:58
【问题描述】:

设置如下:

  1. 创建一个带有 TRichEdit 控件的新 Delphi 7 应用程序。我们在这里讨论的是非 Unicode 应用程序。
  2. 在 Windows 的区域和语言选项中安装一种新的输入语言,其编码与 default Language for non-Unicode programs 的编码不同 - 例如希腊语。
  3. 在应用程序中添加一个按钮,并在其OnClick 处理程序中添加Button1.Caption := RichEdit1.Text;,并将其Font.Charset 设置为您刚刚安装的输入语言的字符集(如果我们坚持这个示例,则为GREEK_CHARSET)。
  4. 运行应用程序,切换到新的(希腊语)输入语言,在 RichEdit 中键入几个字母并按下按钮 - 按钮的标题现在有 ???? 符号而不是希腊字符。

  5. 现在,如果您将 非 Unicode 程序的默认语言 设置为希腊语(需要重新启动 Windows),这个问题就会消失 - 希腊字符会正确显示。将您的非 Unicode 程序的默认语言设置回原来的状态,问题又出现了。

所以我猜 TRichEdit 在内部使用 Unicode,因为更改其 Font.Charset 值不会改变任何东西 - RichEdit 正确接受任何已安装的输入语言,并且如果您安装了两种使用不同字符集的不同非拉丁语言(例如希腊语 /GREEK_CHARSET/ 和俄语 /RUSSIAN_CHARSET/)它会在不更改其 Font.Charset 的情况下同时接受它们。

我还猜想,当您获得 TRichEdit 的 .Text(或 .Lines[i])值时,它会根据 Windws 的非 Unicode 程序的默认语言将其内部 Unicode 文本转换为 ANSI .

此外,将 .Text 值分配给 WideString 或 UnicodeString 也无法正常工作(文本再次在 ???? 中,而不是正确的字符),不仅是当您将其分配给字符串(AnsiString)。

那么问题来了:

我希望能够根据我选择的字符集而不是系统的非 Unicode 程序的默认语言,将 RichEdit 的文本正确转换为字符串 (ANSI)。我怎样才能做到这一点?我更喜欢不涉及第三方组件的解决方案,但是,当然,如果不可能 - 任何事情都可以。

谢谢!

P.S.:切换到 Delphi 2009 或更高版本不是可接受的解决方案。

【问题讨论】:

    标签: delphi delphi-7 richedit input-language


    【解决方案1】:

    向底层富编辑窗口发送EM_GETTEXTEX 消息。您传递了一个 GETTEXTEX 结构,它指定了代码页。

    所以,这样的事情会将文本提取到 UT​​F-16 编码的WideString

    function GetRichEditText(RichEdit: TRichEdit): WideString;
    var
      GetTextLengthEx: TGetTextLengthEx;
      GetTextEx: TGetTextEx;
      Len: Integer;
    begin
      GetTextLengthEx.flags := GTL_DEFAULT;
      GetTextLengthEx.codepage := 1200;
      Len := SendMessage(RichEdit.Handle, EM_GETTEXTLENGTHEX, 
        WPARAM(@GetTextLengthEx), 0);
      if Len=E_INVALIDARG then
        raise Exception.Create('EM_GETTEXTLENGTHEX failed');
      SetLength(Result, Len);
      if Len=0 then
        exit;
      GetTextEx.cb := (Length(Result)+1)*SizeOf(WideChar);
      GetTextEx.flags := GTL_DEFAULT;
      GetTextEx.codepage := 1200;
      GetTextEx.lpDefaultChar := nil;
      GetTextEx.lpUsedDefChar := nil;
      SendMessage(RichEdit.Handle, EM_GETTEXTEX, WPARAM(@GetTextEx), 
        LPARAM(PWideChar(Result)));
    end;
    

    然后,您可以将该 UTF-16 字符串转换为您喜欢的任何代码页。如果您想直接在特定的代码页中将其拉出,请这样做:

    function GetRichEditText(RichEdit: TRichEdit; AnsiCodePage: UINT): AnsiString;
    var
      GetTextLengthEx: TGetTextLengthEx;
      GetTextEx: TGetTextEx;
      Len: Integer;
    begin
      GetTextLengthEx.flags := GTL_DEFAULT;
      GetTextLengthEx.codepage := AnsiCodePage;
      Len := SendMessage(RichEdit.Handle, EM_GETTEXTLENGTHEX, 
        WPARAM(@GetTextLengthEx), 0);
      if Len=E_INVALIDARG then
        raise Exception.Create('EM_GETTEXTLENGTHEX failed');
      SetLength(Result, Len);
      if Len=0 then
        exit;
      GetTextEx.cb := (Length(Result)+1)*SizeOf(AnsiChar);
      GetTextEx.flags := GTL_DEFAULT;
      GetTextEx.codepage := AnsiCodePage;
      GetTextEx.lpDefaultChar := nil;
      GetTextEx.lpUsedDefChar := nil;
      SendMessage(RichEdit.Handle, EM_GETTEXTEX, WPARAM(@GetTextEx), 
        LPARAM(PWideChar(Result)));
    end;
    

    【讨论】:

    • @TLama 你确定RICHEDIT 不支持Unicode吗?
    • this description 至少编辑不应该支持Unicode,但我还没有验证这一点。
    • @TLama 您的链接似乎为 RichEdit 控件 1.0 说明了这一点,即包含在 Windows 98/Me 中的那个,AFAIR。美好的过去……从我的实验来看,RichEdit 组件很长时间以来都是 Unicode。
    • +1 请注意,返回 AnsiString 的函数将适用于 Delphi
    • 你也可以试试EM_SETTEXTEX。您需要定义它和结构。富编辑的版本似乎很难理解。
    猜你喜欢
    • 1970-01-01
    • 2011-05-03
    • 1970-01-01
    • 1970-01-01
    • 2020-02-16
    • 2013-09-04
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    相关资源
    最近更新 更多