Frage

Ich habe eine Delphi 2007 TRichEdit mit mehreren Linien in ihr. Ich mag die Richedit vertikal so bewegen, dass eine bestimmte Zeilennummer, wenn etwa im sichtbaren / Anzeigebereich des Richedit zentriert. Zum Beispiel möchte ich den Code für CenterLineInRichEdit in diesem Beispiel schreiben:

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;

Ich sah in der WM_VSCROLL Nachricht mit, und es ermöglicht Scrollen nach oben / unten einer Zeile, etc., aber nicht Scrollen eine bestimmte Zeile zu zentrieren.

War es hilfreich?

Lösung

Geben Sie diesen einen Versuch;

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;

Die unten ist eine Alternative, dass es zentriert das erste Vorkommen eines Strings statt einer Zeilennummer;

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;

Andere Tipps

Basierend auf den Ideen, die hier kam ich mit einer Lösung auf. Er geht davon aus, dass alle die Linien im Richedit die gleiche Höhe sind und dass die Standardschrift des Richedit korrekt meldet seine Höhe, aber es könnte für einige Leute nützlich sein:

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;

Getestet habe ich diese mit TRichEdit, aber es könnte genauso gut für TMemo arbeiten.

Senden Sie eine EM_LINESCROLL Nachricht an das RichEdit:

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

Siehe EM_LINESCROLL MSDN-Thema .

Sie müssen ein paar Windows-Nachrichten verwenden, um diesen Aspekt Ihrer Kontrolle in einer generischen Art und Weise zu manipulieren:

Sie müssen, wie viele Zeilen berechnen, um nach oben / unten aus der aktuellen Top-Line eine gewünschte absolute Zeilennummer in den Blick zu bringen, aber Sie werden die Anzahl der Zeilen sichtbar in der Steuer berechnen müssen sich (Schriftart verwenden Metriken und Steuerhöhe).

Beachten Sie, dass mit einem RichEdit-Steuerelement der Höhe jeder Zeile kann je nach Schriftart auf den Text in der Steuerung angelegt, um jeder Ansatz basierend auf Zeilennummern allein wahrscheinlich nur annähernd genau sein. Auch ich bin nicht sicher, dass es möglich ist, den aktuellen sichtbaren Bereich der Steuerung (das heißt die Anzahl der Leitungen zur Zeit sichtbar) direkt zu bestimmen, so dass es die Berechnung selbst notwendig ist.

Aus dem Gedächtnis, der SynEdit Steuer bietet einige zusätzliche Kontrolle über solche Dinge, die beide bieten eine Lese- / Schreib TopLine Immobilien sowie ein LinesInWindow Eigenschaft. Aber ich denke, SynEdit nicht Rich-Text-fähig ist, aber wenn dies in Ihrer Anwendung nicht wirklich ein Anliegen ist (dh Sie eine konsistente Schriftart für alle Zeilen des Inhalts verwenden können), dann kann es eine attraktive oder geeignete Alternative sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top