当行数不是太大时,WM_VSCROLL消息没有问题。当 RichEdit 有大量行(在我的例子中是 ~130K 行,平均 150 个字符)时,它不起作用。 RichEdit1.Perform(WM_VSCROLL, MakeWParam(SB_THUMBPOSITION, N), 0);
滚动到顶部 (N> 5) 或超过应有的水平 (N <= 5)。我可以用其他方式进行垂直滚动吗?
附言为了测试可以使用由Sertac Akyuz编写的这段代码。
由于我在问题评论中提到的原因,我想不出一种方法来调整问题中链接的代码以便能够使用丰富的编辑版本 2.0。但幸运的是,这可能没有必要。
对于 Windows XP SP1 及更高版本,操作系统中包含丰富编辑版本 3.0。请参阅 MSDN 上的"关于丰富的编辑控件"。您无需执行任何操作即可使用 3.0 版,2.0 版和 3.0 版的类名相同。如果在系统上部署了3.0版本"riched20.dll",则VCL可以使用它。
有趣的是,WM_VSCROLL
没有问题.消息仍然使用字大小的滚动位置,但丰富的编辑控件会自行调整:您获得的滚动范围最多为 65535。
关于EM_POSFROMCHAR
的问题,对于 3.0 版丰富的编辑控件,如果在 wParam 中传递指向POINTL
的指针,该控件会检测到它,而不是返回坐标,而是填充参数。
所以,这是一个对相同代码略有修改版本的示例(请酌情添加错误/特殊情况处理)(仅适用于设置为 false 的WordWrap
):
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;