2010-11-30 22 views
3

我有一個TLabelEllipsisPosition設置爲epEndEllipsis我需要能夠判斷文本是否被剪裁。除了計算自己顯示文本所需的面積並將其與標籤的實際尺寸進行比較之外,是否有人想出了一種更簡單/更優雅的方式來實現此目的?如何以編程方式最好地判斷TLabel的標題是否被裁剪(即使用省略號繪製)?

實際上,以故障安全方式計算所需面積也不像聽起來那麼直截了當......例如TCanvas.GetTextHeight沒有考慮換行符。

TCustomLabel.DoDrawText內部使用或者 DrawTextWDrawThemeTextExDT_CALCRECT標誌,以確定它是否應使用省略號與否。這裏涉及的代碼很多,全部都是 private。簡單地複製所有代碼並不完全符合我書中的「優雅」...

任何想法?

(我用Delphi 2010的情況下,任何人來了一個特殊的Delphi版本的解決方案)

更新1:我現在想通了,我可以簡單地直接調用 TCustomLabel.DoDrawText(lRect, DT_CALCRECT)(這僅僅是宣佈爲 protected),讓標籤執行所需的大小計算,而不必複製其代碼。我只需要確保臨時設置 EllipsisPositionepNone或完全使用臨時標籤實例。這實際上並不壞,如果沒有人能想到更簡單的解決方案,我可能會採用它。

更新2:我已經添加了我的解決方案作爲單獨的答案。事實證明,這比我預想的更直接,所以可能沒有更簡單/更好的方法來做到這一點,但爲了以防萬一,我將這個問題留出一段時間。

+0

你應該考慮發佈你的解決方案作爲答案。你以後可能會接受它。 – 2010-11-30 12:48:14

+0

@Andreas:如果沒有人提供更好的解決方案,我一直在計劃這麼做,而我目前還在玩弄你的解決方案。 ;) – 2010-11-30 12:52:18

回答

3

FWIW,這裏就是我想出了(這是一個自定義TLabel -descendant的方法):

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設置),它還可以正確處理多行和字符包裝的輸入文本。請注意,在這種情況下,「正確」意味着「當TLabel用剪切標題繪製時,它總是返回True,否則」False「。

雖然上面的代碼做了我最初的要求,但我可能不會這樣使用它 - 但這更多的是由於TLabel本身的缺點:特別是對於多行文本,它往往不會像我想要的那樣行事想要它,例如當沒有足夠的空間用於多行時,即使整行加上省略號會適合,第一行的最後一個字也會被截斷。

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; 

它不會是很難寫出具有使用這種技術一WasClipped屬性TExtLabel組件。的確,TLabel組件是VCL中最簡單的組件之一 - 它只是繪製一個字符串。

相關問題