La meilleure façon de dire si un programme de Légende TLabel est clipsé (à savoir l'aide Dessiné points de suspension)?
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 DrawThemeTextEx
with 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ù.
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