Tlabelのキャプションがクリップされているかどうかをプログラム的に伝えるのが最善です(つまり、Ellipsisを使用して描画されます)?
質問
私は持っています TLabel
と EllipsisPosition
に設定 epEndEllipsis
そして、テキストが現在切り取られているかどうかを判断できる必要があります。テキストを自分で表示するために必要な領域を計算し、ラベルの実際の寸法と比較することに加えて、誰もがこれを行うより簡単な/よりエレガントな方法を思いつきましたか?
実際、必要な領域をフェイルセーフの方法で計算することも、聞こえるほど簡単ではないようです...たとえば TCanvas.GetTextHeight
ラインブレイクを考慮していません。
TCustomLabel.DoDrawText
どちらかを内部的に使用します DrawTextW
また DrawThemeTextEx
とともに DT_CALCRECT
楕円を使用するかどうかを判断するためのフラグ。そこにはかなり多くのコードが関係していますが、それらはすべて宣言されています private
. 。すべてのコードを単に複製するだけで、私の本の中で「エレガント」として正確に適格ではないでしょう...
何か案は?
(Delphi-version固有のソリューションを思いついた場合に備えて、Delphi 2010を使用しています)
更新1: 私は今、私は単に電話できることを理解しました TCustomLabel.DoDrawText(lRect, DT_CALCRECT)
直接(これは単に宣言されています protected
)コードを複製することなく、必要なサイズの計算をラベルに実行させる。一時的に設定するようにする必要があります EllipsisPosition
に epNone
または、一時ラベルインスタンスを完全に使用します。これは実際にはそれほど悪くはありません。さらに簡単な解決策を考えることができないなら、私はそれを使って行くかもしれません。
更新2: 私は今、私の解決策を別の答えとして追加しました。それは私が予想していたよりもかなり簡単であることが判明したので、おそらくそれを行うより簡単な方法はありませんが、この質問はとにかく少し長く開いたままにしておきます。
解決
fwiw、これが私が思いついたものです(これはカスタムの方法です TLabel
-子孫):
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;
これは、まったく同じロジックとまったく同じように使用されるためです TCustomLabel.DoDrawText
(特に人工のパディングと正しいワードラップ設定)また、マルチラインとワードラップの入力テキストを正しく扱います。この場合、「正しく」は「常に戻る」という意味であることに注意してください True
いつ TLabel
切り取られたキャプションで描かれています False
そうでなければ"。
上記のコードは私が最初に求めたことをしますが、私はおそらくこのように使用しないでしょう - しかし、これはの欠点によるものです TLabel
それ自体:特にマルチラインのテキストでは、私が望んでいたように振る舞わないことがよくあります。たとえば、複数の行に十分なスペースがない場合、最初の行の最後の単語は、その行全体とプラスであっても常に切り捨てられます楕円はフィットしていたでしょう。
他のヒント
出発点として、使用できます
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;
サンプルの使用法:
procedure TForm1.FormClick(Sender: TObject);
begin
Caption := 'Clipped ' + BoolToStr(DrawStringEllipsis(Canvas.Handle, Rect(10, 100, 50, 50), 'This is a text.'), true);
end;
書くのは難しくありません TExtLabel
を持っているコンポーネント WasClipped
この手法を使用したプロパティ。確かに、 TLabel
コンポーネントは、VCLで最も単純なコンポーネントの1つです。文字列を描画するだけです。