Использование RichEdit 2.0 одиночного символа CR в качестве переноса строки исключает вычисления SelStart (Delphi XE2) - PullRequest
14 голосов
/ 04 января 2012

При переходе с Delphi 2006 на Delphi XE2 мы узнали, что RichEdit 2.0 внутренне заменяет пары CRLF одним символом CR. К сожалению, это приводит к тому, что все вычисления индекса символов основываются на фактической текстовой строке на стороне VCL.

Поведение, прослеживаемое через код VCL, выглядит следующим образом:

  1. Отправка сообщения WM_GETTEXT (выполнено в TControl.GetTextBuf) вернет текстовый буфер, содержащий пары CRLF.
  2. Отправка сообщения WM_GETTEXTLENGTH (выполнено в TControl.GetTextLen) вернет значение, как если бы текст все еще содержал CRLF символов.
  3. Напротив, при отправке сообщения EM_SETSELEX (то есть настройка SelStart) входное значение будет обрабатываться так, как если бы текст содержал только CR символов.

Это приводит к сбою всех видов вещей (например, подсветка синтаксиса) в нашем приложении. Как вы можете сказать, все отключено ровно на один символ для каждой новой строки до этой точки.

Очевидно, что это противоречивое поведение, мы должны что-то упустить или сделать что-то очень неправильное.

У кого-нибудь еще есть опыт перехода с RichEdit 1.0 на элемент управления RichEdit 2.0 и как вы решили эту проблему? Наконец, есть ли способ заставить RichEdit 2.0 использовать пары CRLF так же, как RichEdit 1.0?

Ответы [ 2 ]

4 голосов
/ 07 января 2012

Мы также столкнулись с этой самой проблемой.

Мы делаем тип «почтового слияния», когда у нас есть шаблоны с кодами слияния, которые анализируются и заменяются данными из внешних источников.

Это несоответствие индекса между pos (mystring, RichEdit.Text) и индексом позиционирования в тексте RichEdit с использованием RichText.SelStart прервало наше слияние.

У меня нет хорошего ответа, но я нашел обходной путь,Это немного громоздко (занижение!), Но пока не будет найдено лучшее решение ...

Обходной путь - использовать скрытый TMemo, скопировать в него текст RichEdit и изменить пары CR / LF только на CR.Затем используйте TMemo, чтобы найти правильное позиционирование, используя pos (string, TMemo), и используйте его, чтобы получить позицию самого начала для использования в TRichEdit.

Это действительно отстой, но, надеюсь, этот обходной путь поможет другим в нашей ситуации илиможет, кто-нибудь умнее меня заставит придумать лучшее решение.

Я покажу небольшой пример кода ...

Поскольку мы заменяем текст с помощью 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 голос
/ 04 марта 2016

Как насчет вычитания EM_LINEFROMCHAR из положения каретки?(ИЛИ позиция EM_GETSEL), в зависимости от того, что вам нужно.

Вы можете даже получить две EM_LINEFROMCHAR переменныеОдин с начала выбора, а другой с нужной позиции каретки / выбора, если вы хотите знать только, сколько пар cl / cr в выборе.

...