我有一个Delphi 2007的TRichEdit,里面有几行。我想垂直滚动richedit,使得特定的行号大致居中于richedit的可见/显示区域。例如,我想在此示例中编写CenterLineInRichEdit的代码:
procedure CenterLineInRichEdit(Edit: TRichEdit; LineNum: Integer);
begin
...
Edit.ScrollTo(...);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
REdit: TRichEdit;
i: Integer;
begin
REdit := TRichEdit.Create(Self);
REdit.Parent := Self;
Redit.ScrollBars := ssVertical;
REdit.SetBounds(10, 10, 200, 150);
for i := 1 to 25 do
REdit.Lines.Add('This is line number ' + IntToStr(i));
CenterLineInRichEdit(REdit, 13);
end;
我研究过使用WM_VSCROLL消息,它允许向上/向下滚动一行等,但不能滚动到特定行的中心。
答案 0 :(得分:3)
向RichEdit发送EM_LINESCROLL消息:
SendMessage(REdit.Handle, EM_LINESCROLL, 0, NumberOfVerticalLinesToScroll);
答案 1 :(得分:3)
根据这里的想法,我提出了一个解决方案。它假设richedit中的所有行都是相同的高度,并且richedit的默认字体正确报告其高度,但它可能对某些人有用:
type
TCustomEditHack = class(TCustomEdit);
procedure CenterLineInEdit(Edit: TCustomEdit; LineNum: Integer);
var
VisibleLines: Integer;
TopLine: Integer;
FirstLine: Integer;
begin
FirstLine := Edit.Perform(EM_GETFIRSTVISIBLELINE, 0, 0);
VisibleLines := Round(Edit.ClientHeight / Abs(TCustomEditHack(Edit).Font.Height));
if VisibleLines <= 1 then
TopLine := LineNum
else
TopLine := Max(LineNum - Round((VisibleLines/2)) + 1, 0);
if FirstLine <> TopLine then
Edit.Perform(EM_LINESCROLL, 0, TopLine - FirstLine);
end;
我用TRichEdit对此进行了测试,但它也适用于TMemo。
答案 2 :(得分:2)
您需要使用几条Windows消息以通用方式操纵控件的这一方面:
您需要计算从当前顶行向上/向下滚动的行数以使所需的绝对行号进入视图,但您必须自己计算控件中可见的行数(使用字体)度量和控制高度。)
请注意,对于RichEdit控件,每行的高度可能会根据应用于控件中文本的字体而有所不同,因此任何基于行号的方法都可能只是近似准确。此外,我不确定是否可以直接确定控件的当前可见范围(即当前可见的行数),因此有必要自行计算。
从内存中,SynEdit control提供了对这些内容的一些额外控制,提供了读/写 TopLine 属性以及 LinesInWindow 属性。但是,我认为SynEdit不具备富文本功能,但如果这在您的应用程序中实际上并不是一个问题(即您可以对内容中的所有行使用一致的字体),那么它可能是一个有吸引力或合适的替代方案。
答案 3 :(得分:2)
试一试;
procedure VertCenterLine(RichEdit: TRichEdit; LineNum: Integer);
// I don't know the reason but the RichEdit 2 control in VCL does not
// respond to the EM_SCROLLCARET in Richedit.h but it does so to the
// constant in WinUser.h
const
EM_SCROLLCARET = $00B7;
var
TextPos: lResult;
Pos: TSmallPoint;
begin
TextPos := SendMessage(RichEdit.Handle, EM_LINEINDEX, LineNum, 0);
if TextPos <> -1 then begin
// Go to top
SendMessage(RichEdit.Handle, EM_SETSEL, 0, 0);
SendMessage(RichEdit.Handle, EM_SCROLLCARET, 0, 0);
// Get the coordinates for the beginning of the line
Longint(Pos) := SendMessage(RichEdit.Handle, EM_POSFROMCHAR, TextPos, 0);
// Scroll from the top
SendMessage(RichEdit.Handle, WM_VSCROLL,
MakeWParam(SB_THUMBPOSITION, Pos.y - RichEdit.ClientHeight div 2), 0);
// Optionally set the caret to the beginning of the line
SendMessage(RichEdit.Handle, EM_SETSEL, TextPos, TextPos);
end;
end;
以下是另一种选择,因为它以字符串的第一次出现为中心而不是行号;
procedure VertCenterText(RichEdit: TRichEdit; Text: string);
const
EM_SCROLLCARET = $00B7;
var
FindText: TFindText;
TextPos: lResult;
Pos: TSmallPoint;
begin
FindText.chrg.cpMin := 0;
FindText.chrg.cpMax := -1;
FindText.lpstrText := PChar(Text);
TextPos := SendMessage(RichEdit.Handle, EM_FINDTEXT,
FR_DOWN or FR_WHOLEWORD, Longint(@FindText));
if TextPos <> -1 then begin
SendMessage(RichEdit.Handle, EM_SETSEL, 0, 0);
SendMessage(RichEdit.Handle, EM_SCROLLCARET, 0, 0);
Longint(Pos) := SendMessage(RichEdit.Handle, EM_POSFROMCHAR, TextPos, 0);
SendMessage(RichEdit.Handle, WM_VSCROLL,
MakeWParam(SB_THUMBPOSITION, Pos.y - RichEdit.ClientHeight div 2), 0);
SendMessage(RichEdit.Handle, EM_SETSEL, TextPos, TextPos);
end;
end;