Il modo migliore per dire a livello di codice se Didascalia di un TLabel è ritagliato (vale a dire disegnato con puntini di sospensione)?

StackOverflow https://stackoverflow.com/questions/4313607

Domanda

Ho un TLabel con EllipsisPosition set per epEndEllipsis e ho bisogno di essere in grado di dire se il testo è attualmente troncato o no. Oltre calcolare la superficie necessaria per visualizzare il testo me stesso e nel confronto con le reali dimensioni dell'etichetta, qualcuno ha escogitato un modo più semplice / più elegante di fare questo?

In realtà, calcolare l'area richiesta in modo fail-safe, inoltre, non sembra essere così semplice come sembra ... Per esempio TCanvas.GetTextHeight non tiene conto le interruzioni di linea.

TCustomLabel.DoDrawText utilizza internamente sia DrawTextW o DrawThemeTextExwith bandiera DT_CALCRECT per determinare se deve usare i puntini di sospensione oppure no. C'è un bel po 'di codice interessata si, ognuno dei quali è dichiarata private. Semplicemente duplicare tutto ciò che il codice non sarebbe esattamente qualificarsi come "elegante" nel mio libro ...

Tutte le idee?

(sto usando Delphi 2010 in caso qualcuno esce con una soluzione di Delphi-versione-specifico)

Aggiornamento 1: ora capito che posso semplicemente chiamare direttamente TCustomLabel.DoDrawText(lRect, DT_CALCRECT) (che è semplicemente dichiarata protected) di lasciare l'etichetta eseguire il calcolo dimensione necessaria senza dover duplicare il codice. Devo solo fare in modo di EllipsisPosition sia temporaneamente insieme a epNone o utilizzare un'istanza un'etichetta temporanea del tutto. Questo in realtà non è poi così male e mi potrebbe anche andare con lui se nessuno può pensare ad una soluzione ancora più semplice.

Aggiornamento 2: Ora ho aggiunto la mia soluzione come una risposta separata. Si è scoperto essere un po 'più straight-forward di quanto mi aspettassi quindi non c'è probabilmente c'è / modo più semplice migliore per farlo ma lascio aperta la questione per un po' più a lungo in ogni caso per ogni evenienza.

È stato utile?

Soluzione

FWIW, ecco cosa mi è venuta (questo è un metodo di un costume TLabel-discendente):

function TMyLabel.IsTextClipped: Boolean;
const
  EllipsisStr = '...';
var
  lEllipBup: TEllipsisPosition;
  lRect: TRect;
begin
  lRect := ClientRect;
  Dec(lRect.Right, Canvas.TextWidth(EllipsisStr));

  lEllipBup := EllipsisPosition;
  EllipsisPosition := epNone;
  try
    DoDrawText(lRect, DT_CALCRECT or IfThen(WordWrap, DT_WORDBREAK));
  finally
    EllipsisPosition := lEllipBup;
  end;
  Result := ((lRect.Right - lRect.Left) > ClientWidth)
         or ((lRect.Bottom - lRect.Top) > ClientHeight);
end;

Dato che questo ora utilizza esattamente la stessa logica TCustomLabel.DoDrawText (specialmente l'imbottitura artificiale e l'impostazione WordWrap corretta) si occupa anche correttamente con più linee e testi di input a capo. Si noti che "correttamente" in questo caso significa "ritorna sempre True quando il TLabel viene disegnato con una didascalia ritagliato e False altrimenti".

Mentre il codice di cui sopra fa quello che ho inizialmente chiesto io probabilmente non usarlo in questo modo - ma questo è più a causa di carenze di TLabel stesso: Specialmente con testo su più righe spesso non si comporta il modo in cui avrei voluto a, ad esempio quando non c'è abbastanza spazio per più righe, l'ultima parola della prima linea sarà sempre troncato anche se che tutta la linea, più i puntini di sospensione avrebbero montato.

Altri suggerimenti

Come punto di partenza, è possibile utilizzare

function DrawStringEllipsis(const DC: HDC; const ARect: TRect; const AStr: string): boolean;
var
  r: TRect;
  s: PChar;
begin
  r := ARect;
  GetMem(s, length(AStr)*sizeof(char) + 8);
  StrCopy(s, PChar(AStr));
  DrawText(DC, PChar(s), length(AStr), r, DT_LEFT or DT_END_ELLIPSIS or DT_MODIFYSTRING);
  result := not SameStr(AStr, s);
  FreeMem(s);
end;

Utilizzo di esempio:

procedure TForm1.FormClick(Sender: TObject);
begin
  Caption := 'Clipped ' + BoolToStr(DrawStringEllipsis(Canvas.Handle, Rect(10, 100, 50, 50), 'This is a text.'), true);
end;

Non sarebbe difficile scrivere un componente TExtLabel che ha una proprietà WasClipped utilizzando questa tecnica. In effetti, la componente TLabel è uno dei componenti più semplici del VCL -. Solo disegna una stringa

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