Delphi:通过滚动在TRichEdit中居中指定行

Delphi:通过滚动在TRichEdit中居中指定行,delphi,line,center,richedit,trichedit,Delphi,Line,Center,Richedit,Trichedit,我有一个Delphi2007 TRichEdit,里面有几行。我想垂直滚动richedit,使特定行号在richedit的可见/显示区域大致居中。例如,我想在本例中为CenterLineInRichEdit编写代码: procedure CenterLineInRichEdit(Edit: TRichEdit; LineNum: Integer); begin ... Edit.ScrollTo(...); end; procedure TForm1.FormCreate(Sender

我有一个Delphi2007 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消息,它允许向上/向下滚动一行等,但不允许滚动到特定行的中心。

向RichEdit发送EM_LINESCROLL消息:

SendMessage(REdit.Handle, EM_LINESCROLL, 0, NumberOfVerticalLinesToScroll);

请参阅。

向RichEdit发送EM\u LINESCROLL消息:

SendMessage(REdit.Handle, EM_LINESCROLL, 0, NumberOfVerticalLinesToScroll);

请参阅。

您需要使用两条Windows消息以通用方式操纵控件的此方面:

  • 检索当前最上面的可见行号(基于0)
  • 向上/向下滚动指定行数的文本
您需要计算从当前顶行向上/向下滚动的行数,以将所需的绝对行号带入视图,但您必须自己计算控件中可见的行数(使用字体度量和控件高度)

请注意,使用RichEdit控件时,每行的高度可能会根据应用于控件中文本的字体而有所不同,因此仅基于行号的任何方法都可能仅大致准确。另外,我不确定是否可以直接确定控件的当前可见范围(即当前可见的行数),因此需要自己计算


从内存中,提供了对这些内容的一些额外控制,既提供了读/写TopLine属性,也提供了LinesInWindow属性。但是,我认为SynEdit不支持富文本,但如果这实际上不是应用程序中的问题(即,可以对内容中的所有行使用一致的字体)然后,它可能是一个有吸引力的或合适的替代方案。

您需要使用两条Windows消息以通用方式操纵控件的这一方面:

  • 检索当前最上面的可见行号(基于0)
  • 向上/向下滚动指定行数的文本
您需要计算从当前顶行向上/向下滚动的行数,以将所需的绝对行号带入视图,但您必须自己计算控件中可见的行数(使用字体度量和控件高度)

请注意,使用RichEdit控件时,每行的高度可能会根据应用于控件中文本的字体而有所不同,因此仅基于行号的任何方法都可能仅大致准确。另外,我不确定是否可以直接确定控件的当前可见范围(即当前可见的行数),因此需要自己计算

从内存中,提供了对这些内容的一些额外控制,既提供了读/写TopLine属性,也提供了LinesInWindow属性。但是,我认为SynEdit不支持富格文本,但如果您的应用程序实际上不关心这一点(即,您可以对内容中的所有行使用一致的字体),那么它可能是一个有吸引力的或合适的替代方案。

尝试一下

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;
过程顶点中心线(RichEdit:TRichEdit;LineNum:Integer);
//我不知道原因,但VCL中的RichEdit 2控件不知道
//响应Richedit.h中的EM_滚动插入符号,但它会对
//WinUser.h中的常量
常数
EM_caret=$00B7;
变量
TextPos:lResult;
Pos:TSmallPoint;
开始
TextPos:=SendMessage(RichEdit.Handle,EM_LINEINDEX,LineNum,0);
如果TextPos-1,则开始
//登顶
SendMessage(RichEdit.Handle,EM_setel,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_拇指位置,位置y-RichEdit.ClientHeight div 2),0);
//(可选)将插入符号设置为行的开头
SendMessage(RichEdit.Handle、EM_setel、TextPos、TextPos);
结束;
结束;
下面是一个备选方案,它将字符串的第一次出现置于中心,而不是行号

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;
procedure-VertCenterText(RichEdit:TRichEdit;Text:string);
常数
EM_caret=$00B7;
变量
FindText:TFindText;
TextPos:lResult;
Pos:TSmallPoint;
开始
FindText.chrg.cpMin:=0;
FindText.chrg.cpMax:=-1;
FindText.lpstrText:=PChar(Text);
TextPos:=发送消息(RichEdit.Handle,EM_FINDTEXT,
FR_DOWN或FR_WHOLEWORD,Longint(@FindText));
如果TextPos-1,则开始
SendMessage(RichEdit.Handle,EM_setel,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_拇指位置,位置y-RichEdit.ClientHeight div 2),0);
SendMessage(RichEdit.Handle、EM_setel、TextPos、TextPos);
结束;
结束;
试试看

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;
过程顶点中心线(RichEdit:TRichEdit;LineNum:Integer);
//我不知道原因,但VCL中的RichEdit 2控件不知道
//响应Richedit.h中的EM_滚动插入符号,但它会对
//WinUser.h中的常量
常数
EM_caret=$00B7;
变量
TextPos:lResult;
Pos:TSmallPoint;
开始
TextPos:=SendMessage(RichEdit.Handle,EM_LINEINDEX,LineNum,0);
如果TextPos-1,则开始
//登顶
SendMessage(RichEdit.Handle,EM_setel,0,0);
SendMessage(RichEdit.Handle,EM_SCROLLCARET,0,0);
//获取直线起点的坐标
Longint(Pos):=SendMessage(RichEdit.Handle,EM_