La meilleure façon de dire si un programme de Légende TLabel est clipsé (à savoir l'aide Dessiné points de suspension)?

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

Question

J'ai un TLabel avec EllipsisPosition ensemble à epEndEllipsis et je dois être en mesure de dire si le texte est actuellement coupé ou non. En plus de calculer la surface nécessaire pour afficher le texte moi-même et en le comparant avec les dimensions réelles de l'étiquette, quelqu'un trouver un moyen plus facile / plus élégante de le faire?

En fait, le calcul de la surface requise de manière à sécurité ne semble pas non plus être aussi simple que cela puisse paraître ... Par exemple TCanvas.GetTextHeight ne prend pas en compte linebreaks.

TCustomLabel.DoDrawText utilise en interne soit DrawTextW ou DrawThemeTextExwith le drapeau DT_CALCRECT pour déterminer si elle doit utiliser les points de suspension ou non. Il y a beaucoup de codes impliqués là, tout ce qui est déclaré private. tout simplement dupliquer ce code ne serait pas admissible exactement comme « élégant » dans mon livre ...

Toutes les idées?

(J'utilise Delphi 2010 dans le cas où quelqu'un vient avec une solution spécifique à Delphi version)

Mise à jour 1: Je maintenant compris que je peux simplement appeler TCustomLabel.DoDrawText(lRect, DT_CALCRECT) directement (ce qui est simplement déclarée protected) pour laisser l'étiquette effectuer le calcul de la taille requise, sans avoir à dupliquer son code. Je dois simplement vous assurer de EllipsisPosition soit temporairement réglé epNone ou utiliser une instance temporaire de l'étiquette tout à fait. Ceci est en fait pas si mal et je pourrais aller juste avec si peut penser à Noone une solution encore plus simple.

Mise à jour 2: J'ai maintenant ajouté ma solution comme une réponse distincte. Il est avéré être un peu plus droite avant que je ne pensais donc il n'y a probablement pas plus facile / meilleure façon de le faire, mais je vais laisser cette question ouverte pour un peu plus longtemps de toute façon juste au cas où.

Était-ce utile?

La solution

FWIW, voici ce que je suis venu avec (ce qui est une méthode d'un TLabel-descendant personnalisé):

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;

Comme il utilise maintenant exactement la même logique que TCustomLabel.DoDrawText (en particulier le rembourrage artificiel et le réglage WordWrap correct), il traite aussi correctement avec plusieurs lignes et textes d'entrée mot enveloppé. Notez que « correctement » dans ce moyen de cas «il retourne toujours True lorsque le TLabel est dessiné avec une légende et tondue False autrement ».

Alors que le code ci-dessus fait ce que je initialement demandé, je ne serai probablement pas l'utiliser de cette façon - mais cela est plus en raison de défauts de TLabel lui-même: Surtout avec du texte multiligne souvent elle ne se comporte pas comme je l'aurais voulu à, par exemple, quand il n'y a pas assez d'espace pour plusieurs lignes, le dernier mot de la première ligne sera toujours tronquée, même si cette ligne entière, plus les points de suspension aurait monté.

Autres conseils

En tant que point de départ, vous pouvez utiliser

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;

Exemple d'utilisation:

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

Il ne serait pas difficile d'écrire un composant TExtLabel qui possède une propriété WasClipped en utilisant cette technique. En effet, la composante TLabel est l'un des composants les plus simples dans la VCL -. Il tire juste une chaîne

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top