3

TLabelwithをにEllipsisPosition設定していてepEndEllipsis、テキストが現在クリップされているかどうかを確認できるようにする必要があります。テキストを表示するために必要な面積を自分で計算し、それをラベルの実際の寸法と比較する以外に、これを行うためのより簡単でエレガントな方法を思いついた人はいますか?

実際、フェイルセーフな方法で必要な領域を計算することも、思ったほど簡単ではないようです...たとえば、TCanvas.GetTextHeight改行は考慮されていません。

TCustomLabel.DoDrawText内部的に、DrawTextWまたはフラグDrawThemeTextExとともにDT_CALCRECT使用して、省略記号を使用するかどうかを決定します。そこにはかなり多くのコードが含まれており、そのすべてが宣言されていprivateます。そのコードをすべて複製するだけでは、私の本では「エレガント」とは言えません...

何か案は?

(誰かがDelphiバージョン固有のソリューションを思いついた場合に備えて、私はDelphi 2010を使用しています)

更新1:コードを複製せずにラベルに必要なサイズ計算を実行させるためにTCustomLabel.DoDrawText(lRect, DT_CALCRECT)(単に宣言されている)直接呼び出すことができることがわかりました。protected一時的に設定EllipsisPositionするepNoneか、一時的なラベルインスタンスを完全に使用する必要があります。これは実際にはそれほど悪くはなく、もっと簡単な解決策を誰も考えられないのであれば、私はそれを使うかもしれません。

更新2:別の回答としてソリューションを追加しました。予想よりもかなり単純であることが判明したので、おそらくそれを行うためのより簡単でより良い方法はありませんが、念のため、この質問をもう少し長く開いたままにしておきます。

4

2 に答える 2

3

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(特に人工的なパディングと正しいWordWrap設定)とまったく同じロジックを使用するようになったため、複数行および単語でラップされた入力テキストも正しく処理します。この場合の「正しく」とは、「クリップされたキャプションなどで描画されたTrue場合は常に戻る」という意味であることに注意してください。TLabelFalse

上記のコードは私が最初に求めたものを実行しますが、おそらくこの方法では使用しませんが、これはそれTLabel自体の欠点によるものです。特に複数行のテキストでは、多くの場合、期待どおりに動作しません。複数行に十分なスペースがない場合、最初の行の最後の単語は、その行全体と省略記号が一致したとしても、常に切り捨てられます。

于 2010-11-30T14:46:52.563 に答える
2

出発点として、あなたは使用することができます

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つであり、文字列を描画するだけです。

于 2010-11-30T12:35:30.440 に答える