Domanda

Ho un TRichEdit Delphi 2007 con diverse linee in esso. Voglio scorrere la RichEdit in verticale in modo tale che un numero di riga specifico se approssimativamente centrato nell'area di visualizzazione / visibile del RichEdit. Per esempio, io voglio scrivere il codice per CenterLineInRichEdit in questo esempio:

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;

Ho guardato in utilizzando il messaggio WM_VSCROLL, e permette di scorrere su / giù di una riga, ecc ma non lo scorrimento di centrare una riga specifica.

È stato utile?

Soluzione

dare una prova;

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;

Il seguente è un alternativo che centra la prima occorrenza di una stringa invece di un numero di riga;

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;

Altri suggerimenti

Sulla base delle idee qui, mi si avvicinò con una soluzione. Si presuppone che tutte le linee nel richedit hanno la stessa altezza e che tipo di carattere di default del richedit segnala correttamente la sua altezza, ma potrebbe essere utile per alcune persone:

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;

Ho provato questo con TRichEdit, ma potrebbe funzionare per TMemo pure.

Invia un messaggio EM_LINESCROLL al RichEdit:

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

Vedere la EM_LINESCROLL MSDN argomento .

Sarà necessario utilizzare un paio di messaggi di Windows per manipolare questo aspetto del vostro controllo in modo generico:

  • EM_GETFIRSTVISIBLELINE per recuperare la corrente, più alto numero di riga visibile (0 basato)
  • EM_LINESCROLL per far scorrere il testo verso l'alto / verso il basso di un numero specificato di righe

È necessario calcolare quante linee di scorrere verso l'alto / dall'alto verso il basso-riga corrente per portare un numero di riga assoluto desiderato in vista, ma si dovrà calcolare il numero di righe visibili nel controllo da soli (utilizzando il font metriche e l'altezza di controllo).

Si noti che con un controllo RichEdit l'altezza di ogni riga può variare secondo i font applicato al testo nel controllo in modo che qualsiasi approccio basato sui numeri di riga da solo rischia di essere solo approssimativamente accurate. Anche io non sono sicuro che sia possibile determinare l'attuale gamma visibile del controllo (vale a dire il numero di linee attualmente visibili) direttamente, in modo da calcolare da soli è necessario.

Dalla memoria, il controllo SynEdit offre alcune ulteriore controllo su tali cose, fornendo sia una lettura / scrittura TopLine proprietà, così come un LinesInWindow di proprietà. Tuttavia, credo che SynEdit Non è un testo ricco in grado, ma se questo non è in realtà un problema nella vostra applicazione (per esempio, si può utilizzare un tipo di carattere coerente per tutte le linee nel contenuto) allora può essere un attraente o valida alternativa.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top