在Delphi 7中,将TMemo
放在表单上,并在表格OnCreate
处理程序中启用RTL BiDiMode
,如下所示:
SysLocale.MiddleEast := True;
Application.BiDiMode := bdRightToLeft;
如果您使用TMemo
将包含BiDi文本的文本文件加载到Lines.LoadFromFile
,则文本将无法正确显示。
让我们在文本文件中包含以下文本(这也是显示它的正确方法,例如当用Notepad ++或MS Word显示时):
!ד asd אב!ג
text... text2...
以下是TMemo
אב!ג asd ד!
...text... text2
以下是该文本存储在文本文件中的方式:
21 E3 20 61 73 64 20 E0 E1 21 E2 0D 0A
74 65 78 74 2E 2E 2E 20 74 65 78 74 32 2E 2E 2E
这里只是一个可视化,它是如何存储的(文本永远不会以任何方式呈现,只是为了说明):
!ד asd ג!בא
text... text2...
因此,BiDi文本保存在交替的"块":(RTL块)(LTR块)(RTL块)(LTR块)等。块从左到右的存储顺序是在正确渲染时,您看到它们的方式(从左到右)与块的顺序相同。每个RTL块中字符的存储顺序与正确显示时这些块中字符的查看顺序相反(参见 alef ,下注,感叹号, gimel 块)。
当RTL BiDiMode
未启用时(如果SysLocale.MiddleEast
的值为False
或BiDiMode
的值为bdLeftToRight
,则文本实际上已正确呈现)。
我测试的其他控件(TLabel
,TCheckbox
,TRadioButton
等)发生了错误的渲染。
当启用RTL TMemo
时,查看BiDiMode
中显示不正确的文本,我发现块的顺序实际上是颠倒过来的。此外,任何前导中性字符(如!
,?
,.
等)都会变为尾随字符,反之亦然(例如文本text2
后面的三个点)。
考虑到这个问题,我认为问题在于Windows' DrawText
函数和呈现BiDi文本时使用的DT_RTLREADING
标志。如果我没弄错,这个函数用于渲染大多数控件中的文本。实际上,如果使用带有DrawText
标记的DT_RTLREADING
在Canvas上渲染BiDi文本,它将以相同的错误方式呈现,如果您不使用DT_RTLREADING
,它将被正确呈现。
我创建了TLabel
的后代类,覆盖了它的Paint
过程,在呈现文本时永远不会使用DT_RTLREADING
,这确实解决了问题。但是,为TCheckbox
,TRadioButton
和TButton
等Windows控件修复此问题并不容易。
我也尝试过使用DrawTextEx
- 问题仍然存在。
我还尝试使用utf8文本文件和TTntMemo
(使用DrawTextW
) - 问题仍然存在。
所以,我的问题是:这是一个已知的问题吗?为什么会这样?如果是,是否有修复方法?或者我在这里做错了什么?