Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > RichEdit и Delphi2010


Автор: CHERRY 14.2.2010, 20:20
Год назад я задавал подобный ворос по Delphi 2009.
Ответа не нашлось. Рискну повторить для Delphi 2010, хотя принципиальной разницы нет.
В RichEdit вставлен текст:
Код

procedure TForm1.FormCreate(Sender: TObject);
begin
  RichEdit.Lines.Append('В белом плаще');
  RichEdit.Lines.Append('с кровавым подбоем,');
  RichEdit.Lines.Append('шаркающей кавалерийской походкой');
end;


Функция
Код

Function TForm1.GetWordOnCaret:String;
var WStart,CaretPos: LongInt;  Mark: string; Flag:Boolean;
Begin
   WStart := RichEdit.SelStart;
   CaretPos:=WStart;
   Flag:=True;
   while Flag do
   begin
     Mark :=RichEdit.Text[CaretPos+1];
     if (Mark = ' ') or (Mark = #$A) or (Mark ='')then Flag:=False Else INC(CaretPos);
   end;
   RichEdit.SelLength := CaretPos - WStart;
   Result:=RichEdit.SelText;
   RichEdit.SelStart := WStart;
End;

возвращает слово справа от курсора до ближайшего пробела или конца строки.
В Turbo Delphi(2006) все работает правильно. В Delphi 2009-2010 все ломается.
В 2006 Selstart перед словом "кровавым" возвращает 17,
а в 2010 возвращает 16.
Если заменить абзацы #$A#$D на пробел, все работает.
Не доганяю. Научите бестолкового.

Автор: Amphiluke 14.2.2010, 20:41
В новых версиях RichEdit символ разрыва строки считается за один-единственный символ (типа "\r"), а не за два CR/LF, как в Rich Edit 1.0.
Цитата(http://msdn.microsoft.com/en-us/library/bb787873(VS.85).aspx)

Rich Edit 1.0 used CR/LF character combinations for paragraph markers. Rich Edit 2.0 used only a carriage return character ('\r'). Rich Edit 3.0 uses only a carriage return character but can emulate Rich Edit 1.0 in this regard.


Вероятно, причина в этом.

Автор: CHERRY 14.2.2010, 20:52
Да я уже сообразил, пока писал вопрос.
Если подсчитывать количество абзацев и корректировать сдвиг по тексту, то вроде работает. Но это не выход.
А если текст мегабайтный. Да и что искать?
Отладчик показавает текст:
В белом плаще#$D#$Aс кровавым подбоем,#$D#$Aшаркающей кавалерийской походкой#$D#$A
Что такое в новой дельфе #$D#$A.
Раньше я мог искать любой из символов #$D или #$A или #$B и было счастье.
Что делать сейчас. Чувствую решение простейшее, но мозгов не хватает.

Автор: Amphiluke 14.2.2010, 21:07
Возможно, я не совсем понял назначение вашей функции, но а что если заменить это:

Цитата(CHERRY @  14.2.2010,  23:20 Найти цитируемый пост)
Код

 if (Mark = ' ') or (Mark = #$A) or (Mark ='')then


на это:
Код

if Ord(Mark[1]) < $21 then




Блин, не то написал. Нет D2010, чтобы потестировать... smile

Автор: DarkProg 14.2.2010, 21:20
Цитата(CHERRY @  14.2.2010,  20:52 Найти цитируемый пост)
#$D#$A


ТОже что и #10 И #13, ничего более

Странно я писал код где нужно было найти символы конца строки и всё было тип топ, в 2010 версии.

Я искал символ #10 а потом смотрел есть ли следующий #13 и если есть то я их удалял(ну мне так надо было и всё работало)

А в чём проблема чтобы взять весь текст из RichEdit скорировать в объект класса Tstrings и там взять сделать поиск нужного, хотя такой метод будет несколько дольше работать и жрать памяти будет тоже больше.

Вообще проблем не должно возникать, может ты хочешь слишком умный код написать???
Я обычно простые вещи пишу просто, если мне нужно слово, на котором стоит курсор, то я бы просто разбил бы строку на две и выделил бы в первой подстроке последний пробел, а во второй первый пробел, ну исоответственно потом процедуры copy  и сложения двух строк(это тупой вариант, но работать должен)

Автор: CHERRY 14.2.2010, 21:26
Цитата(Amphiluke @  14.2.2010,  18:07 Найти цитируемый пост)
код Pascal/Delphi
1:
if Ord(Mark[1]) < $21 then
Блин, не то написал. Нет D2010, чтобы потестировать... 


Я проверил, работает, но...
Что такое $21
Я проверял на начало строки (Mark ='')

Автор: Amphiluke 14.2.2010, 21:35
Я имел в виду, что начиная с символа с кодом $21 начинаются обычные отображаемые символы читаемого текста, а всё, что ниже — либо пробел, либо служебный символ.

Автор: CHERRY 14.2.2010, 21:38
Цитата(DarkProg @  14.2.2010,  18:20 Найти цитируемый пост)
Вообще проблем не должно возникать, может ты хочешь слишком умный код написать???
Я обычно простые вещи пишу просто, если мне нужно слово, на котором стоит курсор, то я бы просто разбил бы строку на две и выделил бы в первой подстроке последний пробел, а во второй первый пробел, ну исоответственно потом процедуры copy  и сложения двух строк(это тупой вариант, но работать должен) 


Я не хачу мудрить. У меня на 2006 рабочая прога.Фирма не ней работает.
Это специфический текстовый редактор с подсветкой определенного синтаксиса.
Все основано на RichEdit.
Все писано мной. Работает идеально не один год вылизую.
Решил ради интереса проверить на 2010. Банан двууглекислый.
Вся подсветка пошла со смещением.
Чем больше абзацев, тем больше сдвиг. Убираю абзацы, все красиво?
Вот такая блин фигня.

Добавлено через 5 минут и 44 секунды
Цитата(Amphiluke @  14.2.2010,  18:35 Найти цитируемый пост)
Я имел в виду, что начиная с символа с кодом $21 начинаются обычные отображаемые символы читаемого текста, а всё, что ниже — либо пробел, либо служебный символ. 

Все работает, кроме слов в начале строки. Может в юникодных версиях абзацы нужно искать не как #$D#$A.
Может это так отладчик по старинке их рисует?

Автор: CHERRY 14.2.2010, 21:56
Извиняюсь 
Цитата(CHERRY @  14.2.2010,  18:38 Найти цитируемый пост)
Я имел в виду, что начиная с символа с кодом $21 начинаются обычные отображаемые символы читаемого текста, а всё, что ниже — либо пробел, либо служебный символ. 

Это не работает.
Работает, если подсчитывать количество абзацев до курсора и учитывать при смещении. Я просто забыл в суете удалть старый код.
Итак мы вернулись в начало.

Автор: Amphiluke 14.2.2010, 22:37
В общем, если проблема в том только, чтобы возвращалось одинаковое значение как в D2010, так и в ранних, можно было бы еще попробовать вот такое:
Код

function TForm1.GetWordOnCaret:String;
var
   WStart,CaretPos: LongInt;  Mark: string; Flag:Boolean;
   ParCount: Integer;
Begin
   if IsWindowUnicode(RichEdit) then
      ParCount := (SendMessage(RichEdit.Handle, EM_LINEFROMCHAR, -1, 0) + 1)
   else
      ParCount := 0;

   WStart := RichEdit.SelStart + ParCount;
.......................


Впрочем, проверить не могу. А смысл все тот же — для юникодного окна пересчитать значение SelStart, добавив нужное значение, чтобы было как с CR/LF. Просто один из способов...

Добавлено через 3 минуты и 25 секунд
Можно, наверное, даже кратче:
Код

function TForm1.GetWordOnCaret:String;
var
   WStart,CaretPos: LongInt;  Mark: string; Flag:Boolean;
begin
    WStart := RichEdit.SelStart + 
        (SendMessage(RichEdit.Handle, EM_LINEFROMCHAR, -1, 0) + 1) * (SizeOf(Char) - 1);

Автор: DarkProg 14.2.2010, 22:37
Цитата(CHERRY @  14.2.2010,  21:26 Найти цитируемый пост)
Я проверял на начало строки (Mark ='')

Это что за, извините, бред, начало строки это символ с индексом 1, а это применимо только к проверке строки на пустоту, не более.

А если курсор в самом начале строки то по твоему коду получится всё равно 1 символ строки исходя из
Код

 Mark :=RichEdit.Text[CaretPos+1];
 

Цитата

Все писано мной. Работает идеально не один год вылизую.

А у тебя код не иделальный, потому что ты юзаешь одну лишнюю переменную, которая называется Flag, и ещё я читал что функция 
Код

inc() 

работает немного дольше чем тупое
Код

a:=a+1


Щас попробую быстренько код сваять, если получится выложу.

Автор: DarkProg 14.2.2010, 22:56
Код

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
    s,slovo:string;
begin
 s:=RichEdit1.Lines[RichEdit1.CaretPos.Y];
 slovo:='';
 for i:=RichEdit1.CaretPos.X+1 to length(s) do
  if s[i]<>' ' then
      slovo:=slovo+s[i]
     else
       break;
ShowMessage(slovo);
end;


Я думаю понятно без коментариев
ТОлько что проверил в D2010

Автор: CHERRY 14.2.2010, 23:14
Цитата(DarkProg @  14.2.2010,  19:56 Найти цитируемый пост)
Я думаю понятно без коментариев

Да, для отделновзятой строки все работает. Но задача не в том, чтобы найти слово справа от курсора в строке.
В общем случае идет поиск в строке RichEdit.Text и единственные отправные точки это #$D#$A
Проблема в несоответствии SelStart c неюникодными версиями Delphi

Автор: CHERRY 14.2.2010, 23:46
Цитата(Amphiluke @  14.2.2010,  19:37 Найти цитируемый пост)
   WStart := RichEdit.SelStart + 
        (SendMessage(RichEdit.Handle, EM_LINEFROMCHAR, -1, 0) + 1) * (SizeOf(Char) - 1);

Код

abz:=(SendMessage(RichEdit.Handle, EM_LINEFROMCHAR, -1, 0) ) * (SizeOf(Char) - 1);


Если ипользовать это для подсчета абзацев, то работает
Код

Function TForm1.GetWordOnCaret:String;
var WStart,CaretPos, abz: LongInt;  Mark: string; Flag:Boolean;
Begin
   WStart := RichEdit.SelStart;
   abz:=(SendMessage(RichEdit.Handle, EM_LINEFROMCHAR, -1, 0) ) * (SizeOf(Char) - 1);
   CaretPos:=WStart+abz;
   Flag:=True;
   while Flag do
   begin
     Mark :=RichEdit.Text[CaretPos+1];
     if (Mark = ' ') or (Mark = #$A) or (Mark ='') or (Mark =#$D)then
     Flag:=False Else INC(CaretPos);
   end;
   RichEdit.SelLength := (CaretPos-abz) - WStart;
   Result:=RichEdit.SelText;
   RichEdit.SelStart := WStart;
End;


Завтра попробую на более сложном тексте.
Всем спасибо за участие.

Автор: DarkProg 15.2.2010, 15:38
Цитата(CHERRY @  14.2.2010,  23:14 Найти цитируемый пост)
В общем случае идет поиск в строке RichEdit.Text 


А в чём проблема взять и засунуть то что я написал в цикл где переменная будет пробегать всё от первой до последней строки и ни надо заморачиваться с символами конца строки

Просто работать со свойством Text обычно несколько геморойно, т.к. надо следить за чудным(и) символом(ами) конца строки, а  так никаких напрягов, и по количеству операций будет по моему работать одинаково.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)