Come mettere CR/LF in un TStringgrid cell?

Voglio avere una fissa riga come intestazione, ma i testi sono piuttosto lunghi, quindi vorrei aumentare l’altezza della riga e inserire CR/LF nella cella di testo.

Googling mostra come una soluzione (ed è la prima cosa che ho pensato fo prima di usare google), ma in basso non vedi al lavoro. Tutte le idee?

Grid.Cells[2,3] := 'This is a sample test' + #13#10 + 'This is the second line';

Quello che succede è che la cella contiene This is a sample testThis is the second line

(Delphi 7, se fa qualche differenza)

[Bounty] “il Mio male. In realtà ho assegnato una risposta di due anni fa, senza controllo, e ora trovare che la risposta non ha funzionato. Aplogies a chi è stato indotto in errore. Questo è un FABOWAQ (frequenti, spesso erroneamente risposto domanda). GINYF”.

Presumo che stiamo cercando di utilizzare OnDrawCell, ma immaginare che ci sarebbe anche necessario aumentare l’altezza delle corde riga della griglia che contiene la cella.

Premierò la risposta per il codice o FOSS VCL component.

[Aggiornamento] deve lavorare con Delphi XE2 Starter edition

  • RowHeights[#] di TStringGrid non aiuterebbe? edit: AFAICS collegati codice nella risposta, RowHeights è utilizzato fino a quel punto.

 

2 Replies
  1. 20

    TStringGrid utilizza Canvas.TextRect, che utilizza ExtTextOut, che a sua volta non supportano il disegno di testo su più righe.

    Devi disegnare autonomamente in un OnDrawCell gestore di eventi con WinAPI del DrawText di routine. Vedi per esempio questa risposta su come utilizzare DrawText per il testo su più righe, e questa recente risposta su come implementare il disegno personalizzato in OnDrawCell:

    type
      TForm1 = class(TForm)
        StringGrid1: TStringGrid;
        procedure FormCreate(Sender: TObject);
        procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
          Rect: TRect; State: TGridDrawState);
      private
        procedure FillWithRandomText(AGrid: TStringGrid);
        procedure UpdateRowHeights(AGrid: TStringGrid);
      end;
    
    procedure TForm1.FillWithRandomText(AGrid: TStringGrid);
    const
      S = 'This is a sample'#13#10'text that contains'#13#10'multiple lines.';
    var
      X: Integer;
      Y: Integer;
    begin
      for X := AGrid.FixedCols to AGrid.ColCount - 1 do
        for Y := AGrid.FixedRows to AGrid.RowCount - 1 do
          AGrid.Cells[X, Y] := Copy(S, 1, 8 + Random(Length(S) - 8));
      UpdateRowHeights(AGrid);
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FillWithRandomText(StringGrid1);
    end;
    
    procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    begin
      with TStringGrid(Sender) do
        if Pos(#13#10, Cells[ACol, ARow]) > 0 then
        begin
          Canvas.FillRect(Rect);
          Inc(Rect.Left, 2);
          Inc(Rect.Top, 2);
          DrawText(Canvas.Handle, PChar(Cells[ACol, ARow]), -1, Rect,
            DT_NOPREFIX or DT_WORDBREAK);
        end;
    end;
    
    procedure TForm1.UpdateRowHeights(AGrid: TStringGrid);
    var
      Y: Integer;
      MaxHeight: Integer;
      X: Integer;
      R: TRect;
      TxtHeight: Integer;
    begin
      for Y := AGrid.FixedRows to AGrid.RowCount - 1 do
      begin
        MaxHeight := AGrid.DefaultRowHeight - 4;
        for X := AGrid.FixedCols to AGrid.ColCount - 1 do
        begin
          R := Rect(0, 0, AGrid.ColWidths[X] - 4, 0);
          TxtHeight := DrawText(AGrid.Canvas.Handle, PChar(AGrid.Cells[X, Y]), -1,
            R, DT_WORDBREAK or DT_CALCRECT);
          if TxtHeight > MaxHeight then
            MaxHeight := TxtHeight;
        end;
        AGrid.RowHeights[Y] := MaxHeight + 4;
      end;
    end;

    Come mettere CR/LF in un TStringgrid cell?


    Ci sono anche altri StringGrid componenti in grado di disegnare il testo su più righe. Per esempio, questo che ho scritto io (fonti per il download: NLDStringGrid + NLDSparseList) forse con questo risultato:

    Come mettere CR/LF in un TStringgrid cell?

    var
      R: TRect;
    begin
      NLDStringGrid1.Columns.Add;
      NLDStringGrid1.Columns.Add;
      NLDStringGrid1.Cells[1, 1] := 'Sample test'#13#10'Second line';
      NLDStringGrid1.Columns[1].MultiLine := True;
      NLDStringGrid1.AutoRowHeights := True;
      SetRect(R, 2, 2, 3, 3);
      NLDStringGrid1.MergeCells(TGridRect(R), True, True);
      NLDStringGrid1.ColWidths[2] := 40;
      NLDStringGrid1.Cells[2, 2] := 'Sample test'#13#10'Second line';
    end;
    • +1 @NGLN io D/L e provare. Eventuali restrizioni sul loro utilizzo?
    • Errore di compilazione – non riesco a trovare DesignEditors.dcu – probabilmente perché sto usando XE2 Starter edition ?
    • Forse, ma non so. Hai convertire il pacchetto di file per XE2? Nota il requires DesignIde linea! Provare runtime altrimenti.
    • Il codice di cui sopra (non il pacchetto), funziona bene – a meno che … se tutte le voci in una riga vuota riga mostra come un pixel di altezza. Può essere predefinito di righe di altezza? Prova questo – in FillWithRandomText() cadere i passanti e assegnare una singola cella (dire Cells[3,3]). Penso che vi saranno mostrati anche il bounty su questo, ma sarebbe bello se si potesse modificare quella riga vuota cosa.
    • Ho cambiato UpdateRowHeights() da MaxHeight := 0; per MaxHeight := AGrid.DefaultRowHeight; e le righe vuote ora ragionevoli.
  2. 5

    Il TStringGrid del renderer di default non supporta più linee. Impostando il TStringGrid in OwnerDraw modalità (richiamando il OnDrawCell evento) è possibile eseguire il rendering di ogni cella tuo piacimento.

    Guardare questo per un esempio che ha aiutato un utente precedente.

    Collegati codice di riferimento inserito:

    procedure DrawSGCell(Sender : TObject; C, R : integer; Rect : TRect;
              Style : TFontStyles; Wrap : boolean; Just : TAlignment;
              CanEdit : boolean);
      { draws formatted contents in string grid cell at col C, row R;
        Style is a set of fsBold, fsItalic, fsUnderline and fsStrikeOut;
        Wrap invokes word wrap for the cell's text; Just is taLeftJustify,
        taRightJustify or taCenter; if CanEdit false, cell will be given 
        the background color of fixed cells; call this routine from 
        grid's DrawCell event }
    var
      S        : string;
      DrawRect : TRect;
    begin
      with (Sender as tStringGrid), Canvas do begin
        { erase earlier contents from default drawing }
        if (R >= FixedRows) and (C >= FixedCols) and CanEdit then
          Brush.Color:= Color
        else
          Brush.Color:= FixedColor;
        FillRect(Rect);
        { get cell contents }
        S:= Cells[C, R];
        if length(S) > 0 then begin
          case Just of
            taLeftJustify  : S:= ' ' + S;
            taRightJustify : S:= S + ' ';
            end;
          { set font style }
          Font.Style:= Style;
          { copy of cell rectangle for text sizing }
          DrawRect:= Rect;
          if Wrap then begin
            { get size of text rectangle in DrawRect, with word wrap }
            DrawText(Handle, PChar(S), length(S), DrawRect,
              dt_calcrect or dt_wordbreak or dt_center);
            if (DrawRect.Bottom - DrawRect.Top) > RowHeights[R] then begin
              { cell word-wraps; increase row height }
              RowHeights[R]:= DrawRect.Bottom - DrawRect.Top;
              SetGridHeight(Sender as tStringGrid);
              end
            else begin
              { cell doesn't word-wrap }
              DrawRect.Right:= Rect.Right;
              FillRect(DrawRect);
              case Just of
                taLeftJustify  : DrawText(Handle, PChar(S), length(S), DrawRect,
                                   dt_wordbreak or dt_left);
                taCenter       : DrawText(Handle, PChar(S), length(S), DrawRect,
                                   dt_wordbreak or dt_center);
                taRightJustify : DrawText(Handle, PChar(S), length(S), DrawRect,
                                   dt_wordbreak or dt_right);
                end;
              end
            end
          else
            { no word wrap }
            case Just of
              taLeftJustify  : DrawText(Handle, PChar(S), length(S), DrawRect,
                                 dt_singleline or dt_vcenter or dt_left);
              taCenter       : DrawText(Handle, PChar(S), length(S), DrawRect,
                                 dt_singleline or dt_vcenter or dt_center);
              taRightJustify : DrawText(Handle, PChar(S), length(S), DrawRect,
                                 dt_singleline or dt_vcenter or dt_right);
              end;
          { restore no font styles }
          Font.Style:= [];
          end;
        end;
    end;

    Credo che questo funzionerà bene per voi…

    • +1 Che sembra buono. Darò un try & tornare a voi. Grazie
    • e ‘ un esempio (in molti punti) di come non si deve scrivere il codice (tranne che non NGLN sottolineato). Il mio suggerimento, non lo uso…
    • Solo leggendo il codice, non vedo dove gestisce più linee incontrando #13#10
    • La prima chiamata a DrawText (con DT_CALCRECT bandiera) calcola il rettangolo necessario per disegnare il testo, che tiene conto di più linee.
    • +1 per replyimng, ma ci possono essere parlando a croce focene. È che la confezione, se una linea è troppo lunga? Se c’è spazio per 12 caratteri e passo ‘a’#13 b’#13 ‘c’ – ottengo tre righe? Voglio essere in grado di dire esattamente dove le interruzioni di riga venire. Grazie per il vostro aiuto @SertacAkyuz
    • Sì, per calcolare la rettangolo per 3 linee. Inoltre se le righe non supera il bordo destro, sarà avvolto da (a causa di DT_WORDBREAK bandiera), in modo che si può finire con più linee.
    • questo appare come un buon codice (ed estremamente flessibile), ma ha un errore di compilazione – che cosa è SetGridHeight ?
    • Il codice è da un forum nel 2003. LU RD ha incollato il codice qui, ho solo collegato al post originale. Tuttavia, io non sono un programmatore Delphi (io uso il C++ Builder) e la stessa libreria VCL come Delphi agli utenti di utilizzare. Potrebbe essere che il TStringGrid componente è stato cambiato dal 2003 (non è la prima volta che si muovono intorno roba). La mia ipotesi è che SetGridHeight() è stato chiamato per forza il cell per ridisegnare stesso e, quindi di cadere in questa routine, ma questa volta l’altezza della cella si adatta il testo intero e verrà redatto. (continua nel commento successivo)
    • (…continua dalla brevious commento) Se il codice funziona senza SetGridHeight() che fa il lavoro nel sottostante VCL. Sono d’accordo che questo non è un buon posto per regolare l’altezza della cella, dovrebbe essere fatto allo stesso tempo, si assegna un nuovo valore alla griglia. A volte si potrebbe non desidera che la cella di variare la dimensione. Tuttavia, è possibile applicare un tappo di valore per il calcolo dell’altezza per consentire solo ad una altezza massima.

Lascia un commento