当从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 2.0像RichEdit 1.0一样使用CRLF
对?
答案 0 :(得分:4)
我们也遇到了这个问题。
我们做了一个“邮件合并”类型的东西,我们有合并代码的模板,这些代码被外部来源的数据解析和替换。
使用RichText.SelStart将pos(mystring,RichEdit.Text)与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;
答案 1 :(得分:1)
How about subtracting EM_LINEFROMCHAR
from the caret position? (OR the position of EM_GETSEL
) whichever you need.
You could even get two EM_LINEFROMCHAR
variables. One from the selection start and the other from the desired caret/selection position, if you only want to know how many cl/cr pairs are in the selection.