delphi - 为什么 EM_SETTEXTMODE 不起作用?

标签 delphi winapi windows-messages richedit trichedit

我正在尝试使用 EM_SETTEXTMODE在 Delphi 7 中的 RichEdit 控件上。

只需创建一个新项目,添加一个 TRichEdit 控件和一个 TButton 控件,并将以下代码添加到按钮的点击处理程序中:

  SendMessage(RichEdit1.Handle, WM_SETTEXT, 0, LPARAM(PChar('')));
  Button1.Caption := IntToStr(SendMessage(RichEdit1.Handle, EM_GETTEXTMODE, 0, 0));
  Button1.Caption := Button1.Caption + ' ' + IntToStr(SendMessage(RichEdit1.Handle, EM_SETTEXTMODE, TM_PLAINTEXT, 0));
  Button1.Caption := Button1.Caption + ' ' + IntToStr(SendMessage(RichEdit1.Handle, EM_GETTEXTMODE, 0, 0));

点击按钮后,按钮的标题设置为 38 0 38,这意味着文本模式根本没有改变 - 最初是 38 (TM_RICHTEXT 或 TM_SINGLELEVELUNDO 或 TM_MULTICODEPAGE),然后 SETTEXTMODE 成功(0),但即使之后它仍然是 38

按照文档的建议,在使用 EM_SETTEXTMODE 之前先清除 RichEdit 的文本。

我尝试使用 EM_SETTEXTMODE 设置不同的值,但它始终保持 38

我注意到 EM_SETTEXTMODE 始终返回 0(成功),即使 RichEdit 控件在调用之前包含文本。

我尝试使用 RichEdit1.Perform 而不是 SendMessage - 没有区别。

我在各个论坛中找到了有关此问题的多个主题,但其中任何一个都没有解决该问题。

知道为什么这不起作用吗?

最佳答案

较旧的 Delphi 版本会加载位于 RICHED32.DLL 中的 RichEdit 控件。 较新的 Delphi 版本会加载 RICHED20.DLL。

RICHED32.DLL 暴露了许多问题,就像你的问题一样。 修复方法是修改 comctrls.pas,以便加载 RICHED20.DLL。这很可能还不够,因为该 DLL 和 VCL 代码可能存在兼容性问题。 查找 TCustomRichEdit.CreateParams() 过程,它包含 LoadLibrary 调用。

我在 Delphi XE 中测试了您的代码,它可以正常工作,因此您最好的选择是升级到更新的 Delphi 版本。

更新

我用Delphi 5做了一些测试,似乎改变2个功能就足够了。 将 Comctrls.Pas 复制到您的项目中并执行以下修改:

1) 在TCustomRichEdit.CreateParams()中,更改

const
  RichEditModuleName = 'RICHED32.DLL';

进入

const
  RichEditModuleName = 'RICHED20.DLL';

CreateSubClass(Params, 'RICHEDIT');

进入

CreateSubClass(Params, 'RICHEDIT20A');

2) 在过程TRichEditStrings.Insert()中,更改

if RichEdit.SelStart <> (Selection.cpMax + Length(Str)) then
      raise EOutOfResources.Create(sRichEditInsertError);

进入

if RichEdit.SelStart <> (Selection.cpMax + Length(Str) - CountLineBreaks(Str)) then
      raise EOutOfResources.Create(sRichEditInsertError);

CountLineBreaks/PosEx 的代码:

function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;
var
 Tmp: PChar;

begin
 Result := 0;
 if (Offset > Cardinal(Length(S))) then exit;
 if Offset = 1 then
  Result := Pos(SubStr, S)
 else
  begin
   Tmp := StrPos(PChar(@S[Offset]), PChar(SubStr));
   if Tmp = nil then exit;
   Result := Cardinal(Tmp - PChar(@S[Offset])) + Offset;
  end;
end;


function CountLineBreaks(const S: string): Integer;
const
  LB = #13#10;
var
  P: Integer;
begin
  Result := 0;
  P := Pos(LB, S);
  while P <> 0 do
  begin
    Inc(Result);
    P := PosEx(LB, S, P + 2);
  end;
end;

在Delphi5中这样做,我得到了正确的结果:

Delphi5

需要记住的一件事是,RichEdit 2.0 将 CRLF 对替换为 CR,因此可能会出现其他问题。如果您在路上遇到问题,请不要向我开枪...

关于delphi - 为什么 EM_SETTEXTMODE 不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21711022/

相关文章:

delphi - Delphi 的 FIX 协议(protocol)引擎?

c++ - 为什么不手动发送 WM_PAINT

c# - Delphi 4 和/或 Delphi 5 可执行文件能否集成到 C# 应用程序中?

Delphi:分离器的对齐和可见性

winapi - XP 通用控制 list : processorArchitecture ='x86' vs. 处理器架构 ='*'

c++ - TrackMouseEvent 不工作

delphi - 将Windows消息发送到另一台计算机

c++ - 如何检测子窗口即时是否按下了ctrl键。 richedit 是焦点?

Delphi,如何避免D2009、D2010中的unicode警告信息

c++ - 从右到左的阅读顺序 : why isn't this calculated automatically?