2

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.

Community
  • 1
  • 1
Branko
  • 1,384
  • 1
  • 16
  • 35
  • Does the problem stay consistent when the file doesn't change? In other words, does the code produce inconsistent results or do you consistently get the same wrong results? –  Jun 04 '12 at 18:44
  • @SilentD Yes, always the same, reproducible. – Branko Jun 04 '12 at 19:04
  • 3
    Scrolling is not the only problem with that code with that many lines. The code uses `EM_POSFROMCHAR` to retrieve the position of a line. `EM_POSFROMCHAR` returns the vertical position in the high-order *word*, which can refer at most to MaxWord (65535). – Sertac Akyuz Jun 04 '12 at 20:45

1 Answers1

1

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;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Thank you, it works!! When I asked the question I was hoping that you will see it :) – Branko Jun 05 '12 at 05:22
  • @Branko - You're welcome! I made a little change to the code so that now it does not have to scroll to top and receive focus. – Sertac Akyuz Jun 06 '12 at 00:57