从Delphi 2006过渡到Delphi XE2时,我们了解到的一件事是RichEdit 2.0在内部用单个CRLF字符替换了CR对。不幸的是,这会导致基于VCL端实际文本字符串的所有字符索引计算中断。

通过浏览VCL代码可以看到以下行为:


发送WM_GETTEXT消息(在TControl.GetTextBuf中完成)将返回包含CRLF对的文本缓冲区。
发送WM_GETTEXTLENGTH消息(在TControl.GetTextLen中完成)将返回一个值,就像文本仍包含CRLF字符一样。
相反,发送EM_SETSELEX消息(即设置SelStart)会将输入值视为文本仅包含CR字符。


这会导致我们的应用程序中的所有事情失败(例如语法突出显示)。如您所知,到那时为止,对于每一个新行,一切都只相差一个字符。

显然,由于这是不一致的行为,因此我们必须丢失某些东西或做一些非常错误的事情。

从RichEdit 1.0过渡到RichEdit 2.0控件的过程中,其他人是否有任何经验,您如何解决此问题?最后,有什么方法可以像RichEdit 1.0一样强制RichEdit 2.0使用CRLF对吗?

最佳答案

我们也遇到了这个问题。

我们进行“邮件合并”类型的操作,其中我们具有带有合并代码的模板,这些模板被解析并替换为来自外部源的数据。

pos(mystring,RichEdit.Text)和使用RichText.SelStart的RichEdit文本中的定位索引之间的索引不匹配破坏了我们的合并。

我没有很好的答案,但是我想出了一种解决方法。这有点麻烦(轻描淡写!),但是直到出现更好的解决方案为止...

解决方法是使用隐藏的TMemo并将RichEdit文本复制到其中,并将CR / LF对更改为仅CR。然后,使用TMemo使用pos(string,TMemo)查找正确的位置,并使用该位置获取在TRichEdit中使用的selstart位置。

这确实很糟糕,但希望这种解决方法可以帮助其他人解决我们的情况,或者激发比我更聪明的人提出更好的解决方案。

我将显示一些示例代码...

由于我们要使用seltext替换文本,因此我们需要同时替换RichEdit控件和TMemo控件中的文本,以使两者保持同步。

StartToken和EndToken是合并代码定界符,并且是一个常量。

function TEditForm.ParseTest: boolean;
var TagLength: integer;
var ValueLength: integer;
var ParseStart: integer;
var ParseEnd: integer;
var ParseValue: string;
var Memo: TMemo;
begin
  Result := True;//Default
  Memo := TMemo.Create(nil);
  try
    Memo.Parent := self;
    Memo.Visible := False;
    try
      Memo.Lines.Clear;
      Memo.Lines.AddStrings(RichEditor.Lines);
      Memo.Text := stringreplace(Memo.Text,#13#10,#13,[rfReplaceAll]);//strip CR/LF pairs and replace with CR

      while (Pos(StartToken, Memo.Text) > 0) and (Pos(EndToken, Memo.Text) > 0) do begin
        ParseStart := Pos(StartToken, Memo.SelText);
        ParseEnd := Pos(EndToken, Memo.SelText) + Length(EndToken);
        if ParseStart >= ParseEnd then begin//oops, something's wrong - bail out
          Result := true;
          myEditor.SelStart := 0;
          exit;
        end;
        TagLength := ParseEnd - ParseStart;
        ValueLength := (TagLength - Length(StartToken)) - Length(EndToken);
        ParseValue := Copy(Memo.SelText, (ParseStart + Length(StartToken)), ValueLength);
        Memo.selstart := ParseStart - 1; //since the .text is zero based, but pos is 1 based we subtract 1
        Memo.sellength := TagLength;
        RichEditor.selstart := ParseStart - 1; //since the .text is zero based, but pos is 1 based we subtract 1
        RichEditor.sellength := TagLength;

        TempText := GetValue(ParseValue);
        Memo.SelText := TempText;
        RichEditor.SelText := TempText;
      end;

    except
       on e: exception do
          begin
          MessageDlg(e.message,mtInformation,[mbOK],0);
          result := false;
          end;
       end;//try..except
  finally
    FreeAndNil(Memo);
  end;
end;

09-17 09:01