【问题标题】:RichEdit and WM_VSCROLL messageRichEdit 和 WM_VSCROLL 消息
【发布时间】:2012-06-08 19:09:45
【问题描述】:

当行数不太大时,WM_VSCROLL 消息没有问题。当 RichEdit 有大量行(在我的情况下约为 130K 行,平均 150 个字符)时,它不起作用。 RichEdit1.Perform(WM_VSCROLL, MakeWParam(SB_THUMBPOSITION, N), 0); 滚动到顶部 (N > 5) 或超过应有的位置 (N

附: 可以使用 Sertac Akyuz 编写的this code 进行测试。

【问题讨论】:

  • 文件不变时问题是否保持一致?换句话说,代码是否会产生不一致的结果,或者您是否始终得到相同的错误结果?
  • @SilentD 是的,始终相同,可重现。
  • 滚动并不是那么多行代码的唯一问题。该代码使用EM_POSFROMCHAR 来检索一行的位置。 EM_POSFROMCHAR返回高位word中的垂直位置,最多可以参考MaxWord(65535)。

标签: delphi windows-7 delphi-xe2 richedit


【解决方案1】:

由于我在问题的评论中提到的原因,我想不出一种方法来调整问题中链接的代码以便能够使用富编辑 2.0 版。但幸运的是,它可能没有必要..

对于 Windows XP SP1 和更高版本,Rich Edit 版本 3.0 包含在操作系统中。请参阅 MSDN 上的“About Rich Edit Controls”。使用 3.0 版不需要做任何事情,2.0 版和 3.0 版的类名是一样的。如果系统上部署了 3.0 版“riched20.dll”,则 VCL 可以使用它。

有趣的是WM_VSCROLL 没有问题。消息仍然使用字大小的滚动位置,但丰富的编辑控件会自行调整:滚动范围最多为 65535。

关于EM_POSFROMCHAR的问题,使用3.0版本的富编辑控件,如果你在wParam中传递一个指向POINTL的指针,控件会检测到它,而不是返回坐标,它会填充参数。


因此,这是一个对相同代码稍作修改的示例(请酌情添加错误/特殊情况处理)(仅适用于 WordWrap 设置为 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;

【讨论】:

  • 谢谢你,它有效!当我问这个问题时,我希望你能看到它:)
  • @Branko - 不客气!我对代码做了一点改动,现在它不必滚动到顶部并获得焦点。
猜你喜欢
  • 2011-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-30
  • 1970-01-01
  • 2017-04-03
  • 2019-09-16
  • 2010-09-22
相关资源
最近更新 更多