在 Delphi 7 中,在表单上放置 aTMemo
并在表单的OnCreate
处理程序中启用 RTL BiDiMode
,如下所示:
SysLocale.MiddleEast := True;
Application.BiDiMode := bdRightToLeft;
如果您随后将包含 BiDi 文本的文本文件加载到TMemo
using 中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、bet、感叹号、gimel块)。
BiDiMode
当未启用 RTL 时(如果SysLocale.MiddleEast
isFalse
的值或 is 的值BiDiMode
),文本实际上会正确呈现bdLeftToRight
。
这种不正确的渲染发生在我测试过的其他控件中(TLabel
、TCheckbox
、TRadioButton
等)。
TMemo
查看启用RTL 时显示不正确的文本BiDiMode
,我看到块的顺序实际上是颠倒的。此外,任何前导中性字符(如!
、?
、.
等)都会变成尾随字符,反之亦然(例如文本后面的三个点text2
)。
调查这个问题,我认为问题在于 Windows 的DrawText
功能和DT_RTLREADING
呈现双向文本时使用的标志。如果我没记错的话,这个函数用于在大多数控件中呈现文本。事实上,如果您使用标志在 Canvas 上渲染 BiDi 文本DrawText
,DT_RTLREADING
它将以同样不正确的方式渲染,如果您不使用DT_RTLREADING
,它将正确渲染。
我创建了一个后代类TLabel
,覆盖了它在渲染文本时Paint
永远不会使用的过程,这确实解决了这个问题。DT_RTLREADING
但是,为 Windows 控件(如TCheckbox
、TRadioButton
和)解决此问题TButton
并不容易。
我也尝试过使用DrawTextEx
- 问题仍然存在。我还尝试使用 utf8 文本文件和TTntMemo
(使用DrawTextW
) - 问题仍然存在。
所以,我的问题是:这是一个已知问题吗?为什么会这样?如果是,有解决办法吗?还是我在这里做错了什么?