1

Delphi2007TRichEditにいくつかの行があります。リッチエディットの表示/表示領域のほぼ中央に特定の行番号が表示されるように、リッチエディットを垂直方向にスクロールしたいと思います。たとえば、次の例で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メッセージを使用して調べたところ、1行を上下にスクロールすることなどはできますが、特定の行を中央にスクロールすることはできません。

4

4 に答える 4

3

RichEdit に EM_LINESCROLL メッセージを送信します。

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

EM_LINESCROLL MSDN トピックを参照してください。

于 2010-05-12T20:28:11.417 に答える
3

ここでのアイデアに基づいて、1 つの解決策を思いつきました。リッチエディットのすべての行が同じ高さであり、リッチエディットのデフォルト フォントがその高さを正しく報告していると想定していますが、一部の人にとっては役立つ場合があります。

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 でも機能する可能性があります。

于 2010-05-15T04:30:27.700 に答える
2

コントロールのこの側面を一般的な方法で操作するには、いくつかのWindowsメッセージを使用する必要があります。

  • EM_GETFIRSTVISIBLELINE は、現在の最上位の表示行番号(0ベース)を取得します
  • EM_LINESCROLL は、指定された行数だけテキストを上下にスクロールします

目的の絶対行数を表示するには、現在のトップラインから上下にスクロールする行数を計算する必要がありますが、コントロールに表示される行数を自分で計算する必要があります(フォントメトリックとコントロールを使用)身長)。

RichEditコントロールでは、各行の高さがコントロール内のテキストに適用されているフォントによって異なる場合があるため、行番号のみに基づくアプローチはほぼ正確である可能性が高いことに注意してください。また、コントロールの現在の表示範囲(つまり現在表示されている行数)を直接決定できるかどうかわからないため、自分で計算する必要があります。

SynEditコントロールは、メモリから、そのようなものに対する追加のコントロールを提供し、読み取り/書き込みのTopLineプロパティとLinesInWindowプロパティの両方を提供します。ただし、SynEditはリッチテキストに対応していないと思いますが、これが実際にアプリケーションで問題にならない場合(つまり、コンテンツのすべての行に一貫したフォントを使用できる場合)、魅力的または適切な代替手段になる可能性があります。

于 2010-05-13T01:31:23.480 に答える
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;
于 2010-05-13T16:05:09.867 に答える