RichView/RichViewEdit - Getting The Text

General TRichView support forum. Please post your questions here
Post Reply
Graham
Posts: 64
Joined: Sun Jan 27, 2013 7:51 pm
Location: Berkshire U.K.

RichView/RichViewEdit - Getting The Text

Post by Graham »

I create some text in a RichViewEdit. I then copy this text Item by Item into a RichView of a fixed width which will define the word wrapping. I now need to get the text on each line. Each Item will return the text which may cover several lines.

Is this possible?

Is there some function like:

tStr := rv.GetLineText (LineNo: integer);
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

There is only GetCurrentLineText in RVGetText.pas (ansi version) and RVGetTextW.pas (Unicode version).

If you want, I can create a function filling a stringlist with text of lines.
But how do you want to process lines in table cells?
Graham
Posts: 64
Joined: Sun Jan 27, 2013 7:51 pm
Location: Berkshire U.K.

Post by Graham »

GetCurrentLineText almost does what I would like.

Is it possible to provide a routine like this:

function GetSpecifiedLineText (rve: TRichViewEdit;
LineNo: integer;
var StyleNo: integer) : TRvUnicodeString;

LineNo is the line number from the top of the display area of rve.
So LineNo = 0 and the function returns the first line of visible text displayed and the associated style number.
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

The first visible line is not strictly defined, because lines may be visible partially.
And line may contain text of multiple styles.
And, does your document contain tables?
Graham
Posts: 64
Joined: Sun Jan 27, 2013 7:51 pm
Location: Berkshire U.K.

Post by Graham »

Ok, lets try and make my requirement slightly simpler (or possibly not).

I'm scrolling the text in a RichViewEdit and I need to determine the text at a particular offset from the top of the visible area. So maybe its easier to use the scroll offset. The top line will be at VScrollOffset, so lets say I would like to get the text at VScrollOffset + 50.

There are no tables involved here but the text on a particular line could contain different styles.

So ideally I would like to have returned some sort of structure that contains the text(Unicode) and a mechanism for determining the style of each character in that text string.
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

I can suggest the following solution.

1) Finding the position in the document at VScrollOffset+50

Code: Select all

var RVData: TCustomRVFormattedData;
     ItemNo, OffsetInItem: Integer;

RichViewEdit1.GetItemAt(0, RichViewEdit1.VScrollPos*RichViewEdit1.VSmallStep[color=red]+50[/color], RVData, ItemNo, OffsetInItem, False);
Without tables, this function always returns RVData = RichViewEdit1.RVData, so we can ignore this variable and use only ItemNo and OffsetInItem.

2) Here is the modified version of GetCurrentLineText from RVGetTextW that returns the line for the specified position (ItemNo, OffsetInItem) instead of the current line:

Code: Select all

function GetineText(rve: TCustomRichViewEdit; ItemNo, OffsetInItem: Integer): TRVUnicodeString;
var i, DNo1, DNo2, DOffs: Integer;
    No1, No2, Offs1, Offs2: Integer;
    s: TRVUnicodeString;
begin
  Result := '';
  rve.RVData.Item2DrawItem(ItemNo, OffsetInItem, DNo1, DOffs, rvdpBetterBelow);
  DNo2 := DNo1+1;
  while not rve.RVData.DrawItems[DNo1].FromNewLine do
    dec(DNo1);
  while (DNo2<rve.ItemCount) and not rve.RVData.DrawItems[DNo2].FromNewLine do
    inc(DNo2);
  dec(DNo2);
  rve.RVData.DrawItem2Item(DNo1, rve.RVData.GetOffsBeforeDrawItem(DNo1), No1, Offs1);
  rve.RVData.DrawItem2Item(DNo2, rve.RVData.GetOffsAfterDrawItem(DNo2), No2, Offs2);
  if No1<>No2 then begin
    if rve.GetItemStyle(No1)>=0 then begin
      s := rve.GetItemTextW(No1);
      Result := Copy(s, Offs1, Length(s));
    end;
    for i := No1+1 to No2-1 do
      if rve.GetItemStyle(i)>=0 then
        Result := Result+rve.GetItemTextW(i);
    if rve.GetItemStyle(No2)>=0 then begin
      s := rve.GetItemTextW(No2);
      Result := Result+Copy(s, 1, Offs2-1);
    end;
    end
  else if rve.GetItemStyle(No1)<0 then
    Result := GetItemText(rve, No1)
  else
    Result := Copy(rve.GetItemTextW(No1), Offs1, Offs2-Offs1);
end;
Last edited by Sergey Tkachenko on Wed Mar 20, 2013 7:33 am, edited 1 time in total.
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

How to get styles of items on this line.

In the procedure above, you can see DrawItem2Item-s return No1 and No2.
To get item styles:

Code: Select all

for i := No1 to No2 do
  add to the list rve.GetItemStyle(i)
Graham
Posts: 64
Joined: Sun Jan 27, 2013 7:51 pm
Location: Berkshire U.K.

Post by Graham »

Perfect. I have changed it slightly such that I pass No1 and No2 as var parameters to the function.

Thanks for your quick response.
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

I forgot "+50", added in the code
Graham
Posts: 64
Joined: Sun Jan 27, 2013 7:51 pm
Location: Berkshire U.K.

Post by Graham »

Yes, I spotted that. I am going to make a further change to your routine such that instead of getting back No1 and No2 I will return a string that contains the style number of each character. So I call the routine and I will get the text for the displayed line and a string of equal length of style numbers.
Graham
Posts: 64
Joined: Sun Jan 27, 2013 7:51 pm
Location: Berkshire U.K.

Post by Graham »

This my current attempt which seems to work.

Code: Select all

function GetSpecifiedLineText(rve: TCustomRichView; ItemNo, OffsetInItem: Integer;
                              var StyleStr: string): TRVUnicodeString;
var i, j, DNo1, DNo2, DOffs: Integer;
    No1, No2, Offs1, Offs2: Integer;
    s: TRVUnicodeString;
    IStyle: integer;

begin
  Result := '';
  rve.RVData.Item2DrawItem(ItemNo, OffsetInItem, DNo1, DOffs, rvdpBetterBelow);
  DNo2 := DNo1+1;
  while not rve.RVData.DrawItems[DNo1].FromNewLine do
    dec(DNo1);
  while (DNo2<rve.ItemCount) and not rve.RVData.DrawItems[DNo2].FromNewLine do
    inc(DNo2);
  dec(DNo2);
  rve.RVData.DrawItem2Item(DNo1, rve.RVData.GetOffsBeforeDrawItem(DNo1), No1, Offs1);
  rve.RVData.DrawItem2Item(DNo2, rve.RVData.GetOffsAfterDrawItem(DNo2), No2, Offs2);

  if No1<>No2 then
  begin
    IStyle := rve.GetItemStyle(No1);

    if IStyle >= 0 then
    begin
      s := rve.GetItemTextW(No1);

      for j := 1 to Length(s) do
        styleStr := styleStr + Char(IStyle);

      Result := Copy(s, Offs1, Length(s));
    end;

    for i := No1+1 to No2-1 do
    begin
      IStyle := rve.GetItemStyle(i);

      if IStyle >= 0 then
      begin
        s := rve.GetItemTextW(i);

        for j := 1 to Length(s) do
          styleStr := styleStr + Char(IStyle);

        Result := Result+s;
      end;
    end;

    IStyle := rve.GetItemStyle(No2);

    if IStyle >= 0 then
    begin
      s := rve.GetItemTextW(No2);
      s := Copy(s, 1, Offs2-1);

      for j := 1 to Length(s) do
        styleStr := styleStr + Char(IStyle);

      Result := Result+s;
    end;
  end
  else
  begin
    IStyle := rve.GetItemStyle(No1);

    if IStyle < 0 then
      s := GetItemText(rve, No1)
    else
      s := Copy(rve.GetItemTextW(No1), Offs1, Offs2-Offs1);

    for j := 1 to Length(s) do
      styleStr := styleStr + Char(IStyle);

    Result := s;
  end;
end;
Post Reply