Question

When number of lines is not too large no problem with WM_VSCROLL message. When RichEdit has large number of lines (in my case ~130K lines with average 150 chars) it not works. RichEdit1.Perform(WM_VSCROLL, MakeWParam(SB_THUMBPOSITION, N), 0); scroll to top (N > 5) or more than it should (N <= 5). Can I do vertical scroll in other way ?

P.s. For testing can be used this code written by Sertac Akyuz.

Was it helpful?

Solution

I can't think of a way to adapt the code linked in the question to be able to work with rich edit version 2.0 for the reason I mentioned in the comment to the question. But luckily it might not be necessary..

For Windows XP SP1 and later rich edit version 3.0 is included with the OS. See 'About Rich Edit Controls' on MSDN. You don't have to do anything to use version 3.0, the class names of version 2.0 and 3.0 are the same. If a version 3.0 'riched20.dll' is deployed on the system, the VCL gets to use it.

Interestingly there is no problem with WM_VSCROLL. The message still use a word sized scroll position, but the rich edit control adapts itself: you get a scroll range of at most 65535.

About the problem with EM_POSFROMCHAR, with a version 3.0 rich edit control, if you pass a pointer to a POINTL in wParam, the control detects it and instead of returning the coordinates, it fills in the parameter.


So, here is a sample having slightly modified version of the same code (please add error/special case handling as appropriate) (works only with WordWrap set to false):

const
  Line = 'The SCROLLINFO structure contains scroll bar parameters...'#13#10;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
  s: string;
begin
  s := '';
  for i := 1 to 130000 do
    s := s + IntToStr(i) + ' - ' + Line;
  SendMessage(RichEdit1.Handle, WM_SETTEXT, 0, LPARAM(PChar(s)));
end;

procedure VertCenterLine(RichEdit: TRichEdit; LineNum: Integer);
var
  LineIndex, MaxLineIndex: lResult;
  LinePos, MaxPos: TPoint;
  ScrollInfo: TScrollInfo;
  ScrollPos: Extended;
begin
  SendMessage(RichEdit.Handle, EM_SETSEL, 0, 0);
  SendMessage(RichEdit.Handle, winapi.messages.EM_SCROLLCARET, 0, 0);
  RichEdit.SetFocus;

  LineIndex := SendMessage(RichEdit.Handle, EM_LINEINDEX, LineNum, 0);
  MaxLineIndex := SendMessage(RichEdit.Handle, EM_LINEINDEX,
      RichEdit.Lines.Count, 0);   // to account for possible line feed at end
  if MaxLineIndex = -1 then
    MaxLineIndex := SendMessage(RichEdit.Handle, EM_LINEINDEX,
        RichEdit.Lines.Count - 1, 0);

  SendMessage(RichEdit.Handle, EM_POSFROMCHAR, WPARAM(@LinePos), LineIndex);
  SendMessage(RichEdit.Handle, EM_POSFROMCHAR, WPARAM(@MaxPos), MaxLineIndex);

  ScrollInfo.cbSize := SizeOf(ScrollInfo);
  ScrollInfo.fMask := SIF_RANGE;
  GetScrollInfo(RichEdit.Handle, SB_VERT, ScrollInfo);

  ScrollPos := (LinePos.y - RichEdit.ClientHeight / 2) / MaxPos.y;
  ScrollPos := ScrollPos * (ScrollInfo.nMax - ScrollInfo.nMin);
  SendMessage(RichEdit.Handle, WM_VSCROLL,
                            MakeWParam(SB_THUMBPOSITION, Round(ScrollPos)), 0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  VertCenterLine(RichEdit1, 110000);
end;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top